Skip to content
C.W.K.
Lesson 06 of 06 · published

The Archive Follows a Role, Not a Name

~14 min · registry, roles, placement, ssh-tunnels, evolution

Level 0Cold Workshop
0 XP0/58 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete

A Ruling Before the Move

On 2026-10-19 a design note about running the family from somewhere other than its usual machines listed eight places that could not be redirected from outside: addresses written as constants, a data root derived from a home folder, guards that refused to start anywhere but one named machine. It asked whether each should get a special seam. The owner rejected the question.

아니지. 그건 CWK 피파 자체가 설계 잘못이지. 왜 그걸 하드 코딩을 하는데? Config 같은 설정 파일로 빼냈어야 하는 거지 그걸 왜 상수로 고정을 시켜? — 아빠

In English: "No. That is a design flaw in CWK Pippa itself. Why hardcode it? It should have been pulled out into a configuration file. Why freeze it as a constant?" The ruling became cwkPippa todo #549: every host, address and data root moves into configuration with one canonical source, and every default stays exactly what it was the day before. Beacon's share landed that evening and night. The Mac that keeps the canonical productions stopped being a spelled name and became whatever the family's port ledger says hosts cwkBeacon. The data root, the travel Mac's label, the checkout and interpreter used over ssh, the engine port in the launchd file (now the token @@PORT:cwkBeacon@@, filled in at install) and the work-order templates followed. With no host profile every value came out identical to before; with one, they moved without a code edit.

What Still Broke

Three days later, on 2026-10-22, the Pippa machine moved to a Mac of its own. The ledger's role changed, and cwkPippa, the voice engine and the transcription engine moved with it. So did Beacon's engine and its archive, because cwkBeacon is one of the members that follow the Pippa machine. Renders did not move. They run wherever the session that took the job runs: the workbench, or the travel Mac.

The registry work held. The tests did not, and neither did three assumptions that no search for a host name would ever have found. That morning five tests still described the old world, asserting the archive Mac's old name and faking a copy that stripped a literal host prefix, so the transfer landed nowhere; they were rewritten to read the archive Mac from the registry. The review the owner had asked for, review 5, found the rest, and his answer to its findings was one line: "이 세션에서 모두 고쳐" ("Fix all of it in this session").

  • Loopback was a host name. Every default address for a sibling was 127.0.0.1, which is a claim that the sibling runs on this Mac. After the move every one of them answered "connection refused", on the workbench and the travel Mac alike.
  • The detour was closed on purpose. The siblings also answer on a tailnet twin, but cwkPippa's sibling doors trust only a caller on their own loopback that carries no forwarded-for header, because the HTTPS twin also brings tailnet browsers in from loopback. A render calling through the twin is refused, and rightly.
  • A boolean was a host name. Handing an accepted production to the archive ran only on the travel Mac. Before the move that meant "every Mac that is not the archive", since the only other Mac that produced was the travel Mac. After it, the workbench was neither, and productions accepted there stayed there: a second writer that nothing synced.

Reach a Member Per Call

The first two fixes live in one module, beacon/reach.py. It asks the registry which Mac a member runs on, and a member that follows the Pippa machine is placed by the ledger's live role rather than by a table copied into every repository, so a role flip reaches Beacon without waiting for a kit sync. Then it resolves an address per call, never at import. A pinned variable wins. A member on this Mac is reached on its own loopback. Anything else is reached through an ssh tunnel to that member's loopback, on its port plus 10000, opened once and left open for the next run. The tunnel arrives at the sibling as a loopback caller with no forwarded-for header, so the doors that refuse the twin let it in, and it rides the ssh trust the machines already share, so no credential was added.

Resolving per call is the point. A module that computed the address at import would freeze the world as it stood when the process started, and a long render would carry yesterday's placement into today. Importing Beacon dials nothing; every call asks the registry again. The one thing that outlives a call is the tunnel, and its check is thin: before opening one, reach asks only whether the local port is already listening. A listening port proves that some tunnel is open, not that it ends at the Mac the ledger names now, so a tunnel opened before a role flip keeps carrying calls to the old Mac until it dies or someone closes it.

One door needed more than an address. The YouTube door reads the movie and the cover from its own disk, so reach.door_path first copies them to the same place in the archive Mac's production tree, resumably, and records the copy in a .door-staged.json beside the production, so that the archive knows those files for what they are: transport, not a production. Review links work the same way: the file goes to where Pippa's upload store lives before the link is minted.

The Second Writer Nobody Synced

The third fix is one condition, changed in two places. Accepting a production, and delivering the offline outbox of archive requests on the next connected take, now run on every Mac that is not the archive Mac, instead of only on the travel Mac.

That change exposed a case the old world never had. The archive Mac often already holds something at a production's place before the sealed production arrives: the movie and cover the door read, or the copy the move itself made. Overwriting it would destroy evidence, and refusing would strand the handover. So the unsealed copy steps aside. Each of its files that the incoming bundle holds byte for byte is a verified twin and is deleted; anything else is kept under incoming/replaced/ for a person to look at. Nothing that is not a verified twin is deleted, and an existing sealed production that differs still stops the install outright.

A Host Name Is a Snapshot of a Role

Every failure in this lesson has the same shape. Someone wrote down which Mac played a role on the day they wrote it: a name in a string, 127.0.0.1 in a default, "the travel Mac" in a condition. Each was true when written, and each became false the moment the role moved, without a single character of it changing. The fix each time was to ask for the role at the moment of use. The archive is no longer a Mac. It is "the Mac the ledger places cwkBeacon on", which today is the Pippa machine and tomorrow is whatever the ledger says.

The ruling three days earlier mattered more than any single fix. Because the spelled names had already moved into the registry, the move broke only the assumptions nobody had recognized as host names, and the review could find every one of them and the owner could have them all fixed in one session.

Name the role, and resolve it when you use it. A host name, a loopback default and a branch on "which machine is this" are three spellings of the same claim: that a role sits on a particular machine. Write the role instead, look up where it sits at the moment you need it, and treat any cached answer as something you can check and throw away.

Code

Where a member runs, by role (verbatim, beacon/reach.py, as of 2026-10-27)·python
def member_host(member: str) -> str:
    """The family host a member runs on: the Pippa machine's for a member that
    follows it (the ledger's live role, so a flip needs no kit sync), else
    the port ledger's table."""
    if member in FAMILY_PIPPA_FOLLOWERS:
        try:
            return role_machine("pippa")
        except KeyError:
            pass
    return str(FAMILY_SERVICES[member]["host"])


def member_label(member: str) -> str:
    """The fleet label (and ssh alias) of the Mac a member runs on."""
    return host_fleet_label(member_host(member)).lower()


def here(member: str) -> bool:
    """Whether the member runs on this Mac."""
    label = _label()
    return bool(label) and label == member_label(member)
Resolved per call, never at import (verbatim, beacon/reach.py, as of 2026-10-27)·python
def origin(member: str) -> str:
    """The base URL this run uses for a member: its pinned variable, its own
    loopback where it runs here, else a tunnel to it. Resolved per call, never
    at import, so importing Beacon never dials anything."""
    pinned = os.environ.get(ENV.get(member, ""), "").strip()
    if pinned:
        return pinned.rstrip("/")
    if here(member):
        return f"http://127.0.0.1:{engine_port(member)}"
    return tunnel(member)
The second writer, closed in one condition (verbatim hunk of register_pending, beacon/storage.py, commit 63bc75e)·diff
     results = []
-    if not is_travel_mac():
+    if is_archive_mac():
         return results

External links

Exercise

Pick a system of yours that spans more than one machine, or could. List every place it assumes where something runs, in three columns: names spelled in code or configuration, loopback or localhost defaults, and conditions of the form "if this is machine X" or "unless this is machine Y". For each entry, write the role it is really naming. Then move one of them to a lookup resolved at the moment of use, and write a test that flips the role in a fixture and checks that the behavior follows without a restart.
Hint
The third column is the one that hides. A condition such as "only the laptop syncs" quietly states that there are exactly two kinds of machine. It stays correct until a third appears, and then it fails silently, by doing nothing. Ask of every such branch what happens on a machine that is neither.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign in — Please sign in to comment.

No comments yet — be the first.