As It Is
This is probably the last post I write before the code base opens. In Ready for Strangers I promised that the next time this journal mentioned the opening, it would be to link the repository, so I am bending that promise by exactly one post. Over the next days I tidy up what a stranger should not have to read. Then it goes out as it is.
"As it is" turned out to be the theme of the last ten days, too. Sooner or later, a system that moves value is asked something it cannot answer. A page asks its server and hears nothing. A payment is ready, but the ledger cannot record it yet. An answer leaves the server and never arrives. The easy thing, every time, is to guess, and software guesses constantly: it draws the page it would draw for an empty answer, or it sends a payment again because the first one never said it had arrived. This release is about not guessing. When the network is not sure, it now says so, in a sentence, and then it does the one thing that is safe.
All of it runs on the production frames, EU, ASIA, their four cloud operators and Frame A, with one exception that lives on the sandbox, where things are allowed to break: the ledger gate. I say so where it comes up. The whole release fits in one picture:
offers the read again
and draws nothing it did not see"]:::a W["the ledger cannot record
(the ledger gate, on the sandbox)"]:::f --> W1["refused before anything moves:
Nothing was moved. Try again shortly."]:::x L["a payment's answer is lost
on its way back"]:::f --> L1["the phone says the send
may have gone through"]:::a L1 --> L2["the next press carries the same key
and gets the same payment back"]:::g B["a balance in the ledger
dips below zero"]:::f --> B1{"are its changes still waiting
in the TEG, for under fifteen minutes?"}:::q B1 -->|"yes"| B2["late: it resolves when they land"]:::a B1 -->|"no"| B3["wrong: a breach"]:::x classDef f fill:#2a1f47,stroke:#7a5cc4,color:#eadcff classDef q fill:#1a2740,stroke:#3f6ea8,color:#dce9ff classDef a fill:#0d3a4a,stroke:#2f8fb0,color:#d6f4ff classDef x fill:#3a1a1a,stroke:#a85454,color:#ffd6d6 classDef g fill:#0b3d2e,stroke:#1f8a5f,color:#d6ffe9
When it cannot see
For a long time the console was an optimist. When a read did not answer, it drew the page it would have drawn for an empty answer: "You have no agents", "All clear.", "0 members". On a bad connection it showed you a world in which nothing had happened, which is comforting, and wrong, and exactly what you do not want from the thing that shows you your money.
The console's own tester, the one that uses it like a person (it was introduced in the last post), now makes every read fail on purpose, one at a time, and writes down what each screen claims. Its first census found six screens that turned a failed read into a fact. The widened one found about 140, across the console, Pocket and the admin pages. Every one of them now says that it could not read, offers the read again, and draws no figure until its read has answered.
6 frames - scroll sideways
Most of them were only misleading. Two could have done real damage. The profile form drew empty fields over a failed read, and Save would have written those empty fields over the real profile. The two-factor panel said "disabled" about an account it had never managed to read, which invites a careful person to switch on something that is already on. A screen that could not see now refuses to act on what it did not see.
The same idea already ran underneath the screens. Since the design review, a permission check that cannot read its data refuses; it never guesses yes. The console has simply caught up with its own server.
When it cannot record
Under every frame there are two books. The TEG holds the balances and is the only thing that moves value. The ledger records every change, and the ledger is what the auditor reads and what anyone can check. Between them sits the TEG's outbox, which hands every change to the ledger in order and exactly once.
Until now, an outbox that could not reach its ledger changed nothing at the front. Payments kept going, the TEG kept every balance right, and the record caught up later. For a few seconds that is harmless. For an hour it would mean value moving that nobody can check yet, which is the one thing this network exists to prevent.
So on the sandbox every TEG now runs a ledger gate. While the outbox is healthy, the gate does nothing at all. While the outbox cannot reach the ledger, the gate refuses every request that would start a movement, before anything moves, and says so in one sentence. The registry, the console and Pocket pass that sentence on exactly as it came:
HTTP/1.1 503 Service Unavailable
Retry-After: 30
Content-Type: application/problem+json
{
"error": {
"detail": "ledger_unavailable: The ledger cannot record this right now. Nothing was moved. Try again shortly.",
"type": "service_unavailable",
"context": {
"headers": {
"Retry-After": "30"
}
}
},
"type": "https://docs.theprotocol.cloud/errors/service_unavailable",
"title": "Service Unavailable",
"status": 503,
"detail": "ledger_unavailable: The ledger cannot record this right now. Nothing was moved. Try again shortly.",
"instance": "/api/v1/teg/send"
}
What happened, what did not happen, and what to do. The error messages this console used to show managed one of the three, and usually not the useful one. A movement that is already under way is allowed to finish, because stopping a trade between its two halves would be worse than letting it complete; its changes wait in the TEG's journal and reach the ledger, in order, once it is back.
5 frames - scroll sideways
For these pictures the ledger of Sandbox Alpha was switched off on purpose, on Monday morning, for 36 seconds. The TEG noticed 22.5 seconds in, refused two movements and none after the ledger was back, the changes that had been waiting drained, the books read zero, and the auditor recorded nothing at all. From 18 October the same drill runs by itself every Sunday evening, because a gate that is only tested when I remember to test it has my memory as its weakest part.
A longer run, ninety seconds, showed one more thing. Five payments that Sandbox Beta had already converted toward Sandbox Alpha waited at Sandbox Alpha's FX router until its ledger was back, and reached their receivers five minutes later. Nothing was lost, but a payment should not sit at a router for five minutes, so the frame that converts now asks the far ledger first, and converts nothing while it cannot record.
One small change made restarts honest as well. A frame's TEG used to start under a shell, and a shell that is the first process of its container ignores the polite request to stop, so every restart ended in a kill ten seconds later and a lease that nobody released. I can respect a process that listens to nobody, but not in production. The TEG itself is now the first process of its container, a restart takes about two seconds, and the lease goes with it.
On the production frames the gate comes next. Like every new refusal on this network, its first step there will be to count what it would refuse, without refusing anything.
When the answer is lost
The hardest question a payment can ask is whether it went through, when nobody answered. A train goes into a tunnel, a registry restarts, a gateway times out, and somewhere a payment may or may not have happened. The person holding the phone is the one who has to decide whether to press again, and a second press used to be a second payment.
That decision is no longer theirs to get wrong. Every request that moves value carries an idempotency key. The console keeps the key when an answer does not arrive. And since this release, the two routes every payment goes through keep each answer that may have been the payment under its key, for a day, and give it again to anyone who asks with the same key. Late on Monday, on Sandbox Alpha, a payment of 0.5 SBXA was sent from a phone, and its answer was dropped on the way back, the way a tunnel would drop it:
4 frames - scroll sideways
The registry had answered the first press with transaction 4e56d624, and the phone never heard it. The second press carried the same key and got the same transaction back. Two presses, one payment, and nobody had to know why.
The rule behind it is short enough to draw:
while the payment runs"]:::a C -->|"a send still running"| WAIT["an earlier send under this key
is in progress: ask again shortly"]:::q C -->|"an answer"| AGAIN["the same answer, given again:
nothing moves a second time"]:::g C -->|"a send that ended
with no answer"| UNK["outcome not known:
never run a second time,
a person reads the ledger"]:::x RUN --> A{"what did it answer?"}:::q A -->|"proof that nothing moved"| FREE["the key is free again"]:::g A -->|"anything else"| KEEP["kept under the key for a day"]:::a classDef f fill:#2a1f47,stroke:#7a5cc4,color:#eadcff classDef q fill:#1a2740,stroke:#3f6ea8,color:#dce9ff classDef a fill:#0d3a4a,stroke:#2f8fb0,color:#d6f4ff classDef x fill:#3a1a1a,stroke:#a85454,color:#ffd6d6 classDef g fill:#0b3d2e,stroke:#1f8a5f,color:#d6ffe9
A key is freed only by an answer that proves nothing moved: a refusal before any value left. Every other answer is kept and given again. A request that ended with no answer at all, because its server stopped halfway, is answered as exactly that, outcome not known, and is never run a second time. A person reads the ledger and settles it, which is slow, and which is the point.
I would rather say plainly that this rule came late. The AGORA venue's gateway pays traders on other frames through the same send everyone uses, and its key remembered only the payments that succeeded. A payment whose answer was lost left nothing behind, so the same key sent it again, and on the sandbox that had paid fifteen traders twice since September, the last of them during the drill that caught it. A drill, it turns out, is a test that charges admission. The gateway now pays again only when an answer proves the first payment reached nobody, the 985 payouts it had left stranded or marked paid without paying went out after a census of the ledger, each one read back, and its key remembers everything now, not only the good news.
A payment that comes back should come back whole, too. When a gateway turned a route down, its payer used to lose two fees of half a percent on the round trip, so a payment of 0.5 SBXB came back as 0.495012. Now the payer's own frame gives both fees back the moment it learns that the payment came back, and a gateway that can only send a payment back later carries the fees in its refund. The payer receives exactly what it sent.
Late is not wrong
The auditor reads every production ledger once a minute, in one statement per frame, and belongs to no registry. One of its checks asks whether anyone's balance in the ledger is below zero. That can happen for an honest reason: the ledger has received a spend while the credit before it is still on its way. Until now the auditor called that a breach. It is not a breach. It is late.
Version 2.5.0 asks the TEG. If an agent's changes are still waiting in the TEG's journal, and the oldest of them is younger than fifteen minutes, the balance is behind and resolves when they land. If nothing is waiting, or something has waited longer than that, it is a breach, as before. Every cycle the auditor also counts the TEG's own negative balances directly, a number that should always be zero, and a count it could not read is reported as not checked, never as zero.
2 frames - scroll sideways
Before it went live, the new version ran beside the old one for an hour, over the same frames: thirty rounds of five frames, and the two agreed on every one. Then it took over with the same signing key, the same history and the same chain of attestations. The chain did not notice the change of hands, which is the whole point of a chain.
The first members
On the production frames, the change of the last post now has names behind it. A developer becomes a member of a registry once one of their agents has held its bond there for thirty days, and EU's first members crossed that line on 7 October. Today EU has two members and ASIA one, every vote on both frames is a member's, and neither has opened a commons season yet.
Three members on two frames is not a crowd. It is, however, a quorum of people who chose to be there, which is the only kind I have ever trusted.
Who builds this
A repository tells you a great deal about a project and almost nothing about the person behind it, so before mine goes out, a few words about that.
This network is built by one person. I used to do IT support for a living. These days this is my full-time work, and most of it is learning, because I would rather not fall behind while people are still part of this kind of work. Full time turns out to have no closing hours, which is why so many of the times in this journal are after midnight. I once wanted to build things like this inside the tech industry. The industry decided it could do without me, and not every hand on that door belonged to a stranger. Since then the project has been fought on more levels than I knew a project had. I will not go into them here. They are not what this journal is for.
I am fine. I was always fine. I am doing what I am doing, and nothing has stopped it so far, which I take as a fair forecast. I wrote about the price of building this alone once before, in Twenty-One Blueprints, Drawn Alone. The price has not gone down, and I am still paying it on schedule.
It also explains the software better than any diagram in it. Build as if nobody will ever vouch for you, and you end up with books that anyone can check without asking you, refusals that say why, and a payment that happens once whether or not anyone is watching. Most of this release fits in that sentence.
As it is
Step back from the screenshots, and this release changes one thing: what the network says when it is not sure. A screen that could not read says so. A payment the ledger cannot record does not happen, and says why. A payment whose answer was lost is answered again, never sent twice. A balance that is late is called late, and a balance that is wrong is still called wrong. None of it makes the network faster, and none of it would look good on a poster. It is the part of a system you only notice when it is missing, usually at the worst possible moment.
That is also what goes out in the next days. Not a polished subset and not a demo, but the network as it is: the frames and their TEGs, the ledger and its auditor, the console and the tester that uses it like a person, the kit, the gates, and the tests that hold what every run so far has taught them. Whoever picks it up can start from where I stopped, which was always the point.
The next time this journal mentions the opening, it will be to link the repository. This time I mean it.
Patchnotes
The last post went out with V0564, the release that switched the production frames to membership. What follows is V0565 through V0606, ten days of work, every version on the sandbox before any production frame, with the supply delta at zero throughout on every frame the auditor watches: its breach log has no entry since August. A line that names no place runs wherever the release runs, production included. "On the sandbox" marks the one part this release does not carry to production: the TEG's and the store's half of the ledger gate, which goes to production next and starts there by counting what it would refuse.
Membership on the production frames
- EU's first members joined on 7 October, the day their bonds had been held for 30 days. Today EU has two members and ASIA one, and neither has opened a commons season yet.
- A commons submission whose author has the same display name as another member carries the tail of its DID, so the ballot names the right one (V0565).
- /architecture names membership governance where a registry runs it, /governance-docs is generated from the code, and every public page states the voting mode only once the registry has answered (V0566, V0568, V0572).
- The reputation bond is a deposit in every language the console speaks (V0571).
The console says what it could not read
- A read that failed is never shown as "none", "off", a zero or an all-clear. About 140 screens, panels and counters across the console, Pocket and the admin pages now say that a read failed, and draw no figure until their read has answered (V0567 to V0577, V0588, V0589).
- Among them: My Agents said "Fleet is empty", the bell said "All clear.", the Guild board said "No open tasks", the simulation console said STOPPED with its start button live, and the identity theatre said SPIRE FABRIC NOMINAL, each over a read that had failed.
- Two of them could have written over real data: the profile form showed empty fields over a failed read and its Save would have stored them, and the two-factor panel read "disabled" for an account it had not read. Both refuse to act on a read that did not answer.
- Pages that read another frame or another listing draw only what their latest read answered: the AGORA desk no longer shows one listing's book under another's symbol, and the treasury, FX, bridge and settlement desks never draw one frame's figures under another frame's button.
- My Agents draws its fleet count and balances only over a fleet read that answered, and the sidebar calls only a visitor without a session a guest: a session whose account could not be read says so, with Try again (V0601).
- Pocket's activity draws only its newest read, so one agent's own record never shows another scope's rows (V0601).
- A read whose page is already gone raises no message on the next page (V0589), and a view whose code cannot be loaded reloads once instead of breaking (V0591).
- The saved agent comes back after the registry was unreachable when the page loaded (V0573, V0574).
- Settings is reordered, its address names the open tab, and the two-factor panel's text is set at the size of its neighbours (V0572, V0573).
Sending and paying
- The console never sends a write a second time on its own, and every request that moves value carries an idempotency key (V0574).
- A send that got no answer may still have gone through: the console and Pocket say exactly that, and the next press carries the same key, so it can never pay twice (V0576).
- The smart send's currency preview asks for the quote that knows the receiver, and Pocket names the unit a cross-frame payment arrives in (V0590).
- The AGORA settlement worker keeps part of every cycle for its lighter batches, so a busy market no longer makes refunds wait for a quiet one (V0589).
- A treasury funding leg whose source another funding drained at the same moment reads the source again and takes the rest from the next one in line (V0582).
- A denial above an agent's approval threshold says what happens next, and the agent access panel names a refusal in the registry's own words (V0590).
When the ledger cannot record
- Every TEG on the sandbox runs the ledger gate, in enforce on both frames since 11 October and on both cloud operators since the same evening: while its outbox cannot hand balance changes to the ledger, it refuses every request that would start a movement, with a 503, a Retry-After header and the sentence "The ledger cannot record this right now. Nothing was moved. Try again shortly."
- Under the gate, a movement that is already under way is allowed to finish, so a trade or a cross-frame transfer that began before the outage completes and is recorded when the ledger is back.
- A payment into another frame is refused before anything converts while that frame's ledger cannot record it, with the TEG's own sentence, rather than waiting at the FX router for the ledger to come back; a payment an operator started comes back to the person, and says so (V0602, V0603).
- The registry, the console and Pocket pass the refusal on as it came, on every send path and every caller that starts a single movement, and never call it a server error or say it may have gone through (V0596 to V0598).
- On the sandbox, each TEG runs as the first process of its container, so a restart is graceful and the outbox's lease is released at once (restarts of 1.1 to 2.2 seconds).
- A store outage drill runs on Sandbox Alpha every Sunday evening from 18 October: the store is stopped, the console's own suite checks that nothing moved and that the sentence reached the screen, the store is started again, and every check of the ledger has to come back clean. The first drills on 11 October found one thing on screen: an AGORA order's refusal reached the person twice, the second time as a bare code word. V0599 says it once, and the last drill that day was clean on every check.
- A first agent's grant that its frame could not pay is owed and paid later (V0598); where the euro lane is switched on for testing, a paid credit that did not land is owed and credited with the purchase's own key, and an account deletion's forfeiture that moved nothing is owed and drained later (V0599).
- On the sandbox, the store marks a negative projection and counts it, without refusing the event that caused it.
- The production frames' own store, with the negative mark added and nothing else changed, is built: its whole suite, the supply invariant and the mark on a real database all pass.
Paying once
- The AGORA gateway's payout lane sends a payout again only when its answer proves the payout reached nobody, and holds anything else for a ledger read; a 200 whose body says "failed" is no longer marked paid, and a payout at its attempt limit is no longer left where nothing looks again (V0603).
- On the sandbox, 933 payouts the lane had left stranded and 52 it had marked paid without paying were paid on 12 October, after a census of the ledger proved that none had gone out, each one read back in the TEG; three amounts left stranded by earlier FX swaps went back to their gateways.
- The FX booth and the route's hop refund a payer only when the paying leg provably never ran: a leg whose answer was lost is asked again under its own key until its outcome is known, and a route whose outcome stays unknown is held for a ledger read (V0604).
- A route the receiving frame's ledger could not record answers "Your payment came back to you" with its Retry-After, and the console reads it as a refusal, never as a send that may have gone through (V0605).
- A payment a gateway sends back costs its payer nothing: the payer's frame gives back both fees the moment it learns the payment came back (V0605), and a gateway that can only send it back later carries the fees in its refund (V0606).
- An idempotency key keeps every answer that may have been the payment and gives it again; only an answer that proves nothing moved frees the key, and a request that ended without an answer is answered "outcome not known" instead of being run a second time (V0606).
- The console keeps the key of a send whose answer below 500 says the outcome is not known, or that an earlier send under the same key is still running, so the next press is answered with what that send left (V0606).
- A local transfer whose TEG batch failed or timed out says that its outcome is not known instead of "Transfer failed", and a transfer the cross-worker queue may still hold is never sent again another way (V0606).
- A refund whose outcome is not known is held for a ledger read and never sent again on its own (V0606).
The auditor
- Version 2.5.0: the per-user check tells a projection that is only behind the TEG (the TEG still holds the agent's balance changes, the oldest for less than fifteen minutes) from a breach, and counts the TEG's own negative rows every cycle. A census that could not be read is "not checked", never OK. Before it went live it ran beside the live auditor over the same frames, and the two agreed on every frame in every round.
- The attestation format, the invariant verdict and every key of the public read are unchanged.
Getting started
- /onboarding issues an agent identity from a name, lists your agents with their balances masked by default and resets an agent's credentials; and a lost secret is pointed to Reset credentials (V0586, V0587).
- The quick agent sheet makes a wallet only when your agents were read and there are none, and mentions locks only where the registry offers them (V0577, V0587).
- The registration form asks for an invitation only where the registry requires one (V0577).
- The phone's approval page follows its request and says when no fingerprint was given, and a sign-in waiting for the phone says how it ended, counts down and can be stopped (V0592).
- A password reset that got no answer is not called sent, a used reset link is refused in words that fit it, and the reset page's timer stops when you leave it (V0592, V0594).
Organizations and mail
- An organization invitation is stored first and mailed second, says whether its mail was sent, and links to the console its members sign in on (V0592, V0594).
- A broadcast to one organization reaches its members only, live and scheduled, and says so (V0592).
- A mail subject that names an amount names the frame's own unit (V0591).
- Every count of developers and every recipient list means the developers of this registry, never a deleted account or a placeholder for another frame's (V0594).
- The Invitations tab is on every registry (V0595), and a webhook that has ever delivered can be deleted, and so can its owner's account (V0582).
Cloud operators
- A cloud operator is provisioned with its own push relay behind a door that only subscribes, and with its own policy engine, deciding in shadow beside the code (V0582).
- A registry serves the settings an operator may choose, the operator application offers them, and the provisioner writes the choices (V0595).
- A registry says what it runs (the liability mode, contract templates, the sandbox proxy), and the console asks for nothing a registry does not run (V0593).
- A frame is born with its registry's database pool sized to its database (V0591).
- Cross-registry delegation is in the agent access panel (V0595).
- The operator page states the posture of the Federation Operator Terms and links them (V0581).
Access rules, now on every production frame
- A TEG decides its admin role by the caller's relation to it: its own services keep every admin route, a peer frame's registry gets the two routes the FX pool needs and nothing else, and any other identity gets none (V0583, every TEG of EU, ASIA and their operators since 7 October).
- Pocket asks for the admin phone list only on an admin's behalf, and the attention panel asks for the funding queue only on a treasury admin's (V0578, V0592).
- The routes for a device's signing key no longer depend on the liability mode (V0593).
- The operator portal sends its federation licence only to a parent whose certificate verifies (V0549, on every production frame since V0564).
- A 401 names its challenge on the wire as well as in its body (V0600).
Federation and discovery
- A frame's own cards no longer come back to it, and a returned copy that has not changed is silent: the log warning storm the monitoring reported was a sandbox frame refusing its own cards (V0588).
- The card pull never asks the registry's own hosts (V0584).
- Discover cuts its pages from one total order, so a walk over all its pages meets every card exactly once (V0585, V0594).
- A frame from the kit or the template syncs every 30 seconds, like the production frames, and the documentation's federation chapter measures the interval, the topology and how fast a change travels (V0584, V0585).
Identity, policy and the platform
- The node attestation authorities of all four frames were issued again, valid until 2036, and every local operator's bootstrap bundle is refreshed every hour.
- The policy engine runs in shadow on EU, ASIA and their four operators since 6 October, deciding beside the code without being able to refuse; on EU it agreed with the code on all 17,968 decisions it made between 11 and 12 October.
- Push runs on all six production nodes through its own relay.
- Frame A runs the same release as the other production frames, with the same posture, from V0520.
- The nightly pair is built from exactly the images production runs or refuses to start, and a frame made in Frame Management starts on the newest images.
- Frame kits 1.0.0-beta.18 (the policy engine's metrics and alerts, and push) and 1.0.0-beta.19 (a sync every 30 seconds); the release channel stays dark.
- Every template a frame or a cloud operator is born from starts its TEG as the first process of its container, and the frame template declares the ledger gate's mode, off until a frame's TEG carries the gate.
Monitoring
- The console's header reads the alerts the alert engine actually holds (it had asked a path that does not exist, on every refresh), and a firing critical holds back its own warning (V0580, V0581).
- A critical alert repeats every four hours, a warning and a critical about the same thing count as one, and the alert rules lost the leftovers of the retired frames.
- Memory alerts read the working set, and the card pull's ratio rules divide what they meant to.
- The frame kit shows the policy engine on its dashboard and alerts on it.
Public pages, documents and legal texts
- The whitepaper, the in-app documentation and the public compliance documents describe the network as it runs (V0567), and the documentation follows the registry's switches (V0595).
- /status and /architecture draw no figure before their read has answered, and every public page has one main landmark and a skip link that lands (V0565, V0570).
- Terms 2.4 in legal set 2.5, effective 3 November: membership and the commons, and AGORA priced in the frame's own unit (V0571).
- The guided tours, the tutorial hub and the euro pages name the frame's own unit (V0596, V0597, V0599).
- Diagrams in the documentation are laid out off the page, so a hidden or replaced article draws nothing broken (V0600).
Smaller things
- The confirmation dialog for a sensitive step holds the keyboard: focus enters it, Tab stays inside and Escape cancels (V0586).
- A notice is drawn above every page, panel and dialog, so the beta banner no longer covers its title, and Pocket's agent list no longer names a feature its registry has switched off (V0601).
- A display name in another script keeps a card handle of its own, and the quick sheet shows the handle it sends (V0586).
- The announcement bar is a Settings option, and the bell opens the broadcast it names (V0580).
- An agent you own is switched to directly from the agent picker, which the switcher's own dropdown no longer covers (V0590).
- An answered decision keeps its outcome on screen, and an operator's founding date stays on a card saved in the editor (V0592).
- The flare shop says when its catalog or its receipts could not be read, and the desk keeps its signing key when a prompt is cancelled and forgets one the registry refuses (V0594).
- A cloud operator's portal has its Account tab, the federation test page says when no sandbox is connected, and Pocket's network board buys a listing at its home venue (V0593).
- registry-config reports the retired bridge, and the testers hold the bridge tools to their refusal (V0585).
Tests
- The console suite runs every night beside the MCP tester, and its runs appear in both histories; a second nightly pass runs on a sandbox frame with every switch on, and the sandbox's two cloud operators are targets of their own, each with its own mail catcher.
- The API tester's group cards follow the catalog the registry serves (ten cards reach all 1,255 endpoints), the MCP tester's federation suite casts a home registry's ballot from its members where it has members, and its ledger row waits for the store to catch up (V0578, V0579, V0585).
- The registry's whole suite runs inside every image before it rolls: from 6,824 tests at V0564 to more than 7,300 at V0606, none failed. Every fix brought a test that fails on the release before it.
- A contract rule fails the build when a template starts the TEG without making it the first process of its container, or leaves the ledger gate's mode undeclared.