The Address Moved Again
The previous lesson handed ports and hosts back to the family's registry: no template variable may carry an address, and every script asks the registry at run time. That made the registry the one owner of where things are. In late October the owner of the whole family asked a harder question of it: what happens when the family moves to a different Mac?
His ruling set the bar in one sentence. Moving the family from one machine to another should be one ledger edit plus a data sync — and it should work the same way for every later move, not only this one. A registry that names machines cannot do that. Every claim in it said, in effect, "this service runs on that Mac", so a move meant rewriting every claim, and every consumer that had learned a machine's name would have to be found.
Claims Name a Job
So the port ledger learned to name roles. A claim can say @pippa — the machine that runs every service, holds the live data and owns the single-instance writers. It can say @workbench — where code is written and where the fleet's writer runs. It can say @each — a per-machine instance that every Mac runs as itself. Or it can still name one machine, when something is pinned there on purpose, like a tool bound to one Mac's hardware. A separate roles table says which machine holds each role today. A move is a change to that table.
Three details carry the design:
- Roles are resolved before the collision checks. The generator that renders the registry still refuses a member claimed on two hosts, so a role cannot be used to smuggle a duplicate past the rule.
- Roles are read live. The kit's readers consult this machine's copy of the ledger at the moment of asking. A flip of the role, or its revert during a rollback, reaches a running service without a restart and without a kit deploy.
- A saved choice is not a default. A host somebody chose and saved for a specific purpose keeps meaning that machine. Only defaults follow the role; changing the role must never retarget a choice a person made.
Who Is Allowed to Speak
Moving addresses is the easy half. The hard half is everything that writes: scheduled jobs, a chat bot, a publisher, the single writer of the coordination database. During a move there are two machines that could each believe they are home. If both answer, a message gets two replies and a post goes out twice.
So every such writer asks the kit one question before it acts — is the single writer here? — and the answer is yes on the machine that holds the role. The one other yes is a standby replica the family can be hosted from in an emergency, and there every such writer stays held until the owner switches it on. A Mac being prepared for the family stays silent; so does the old Mac after the move. A writer that reaches outside its machine asks one more thing: has this machine heard the ledger recently? A Mac that follows origin by itself records each follow that landed. If it has not confirmed one for thirty minutes, its outward writers hold, because the family may have moved and it would not know. A rollback written at origin reaches such a machine within minutes, even when nobody can log into it.
A Guard That Reads Use, Not Words
Roles only help if nobody pins a machine by hand again. So the kit gained a guard that checks every newly staged line in every repository, through the family's shared commit hook, and fails a runtime default that names a physical machine. A default that should follow a role must ask the role; that class of finding cannot be exempted.
Its first version taught the guard's real rule. Most of the family's machine names are ordinary English words, and a checker that matched the word refused to publish a diary sentence that merely mentioned one. The owner called the checker itself the defect. The guard now matches a name only where it is used as a machine: as the target of a remote shell or copy command, as a host in a URL, as a key in a mapping of machines, as a value assigned to something that holds a host, as a fallback default. In prose, a comment or an identifier it is a word, and words pass.
What the Ledger Could Not Move
The first move ran over three days in late October, and every service has run on the new machine since its second day. It did not turn out to be one edit. The code-side facts moved with the role; what the code could not see did not — privacy permissions granted to one machine, keychain items, network mounts, addresses already installed on phones. Each of those became a step in a written runbook, with a check before it and a check after, so the next move starts from the inventory instead of discovering it. The role turned a migration into an edit for everything that asks the ledger. The runbook exists for everything that never did.