v0.12.0 — a window into a colony that is already running #164
mmeyerlein
announced in
Announcements
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
v0.12.0 is out. Three issues, and the first one is the kind of limit you only find by trying to use the thing you built.
A surface installs into a colony that is already running
Since v0.11.0 a cell can declare
cell.surfaceand the binary serves it — a page, its own assets, a websocket, all under one prefix. What nobody had tried until yesterday was adding one to a colony that was already up. It turned out to be impossible, and for a reason that had nothing to do with surfaces:-> /.-> /leaves every subtree.A surface could therefore only be created at a colony's first boot, which is a bad limit for a feature whose whole point is looking at cells that are running. Two rules moved (#163):
The door is not a place.
EgressPolicynow decides where it opens as well as what leaves.All(Direct-Mode, where stdout is the only consumer) stays root-only — a dead end deeper in the tree is a real dead end and belongs in the dead-letter queue.Markedneeds no geography: the marker lives incontext, only the layer that injected the request can mint one, and a cell cannot writecontextat all. So a marked message is by construction the answer to a request somebody is holding a socket open for, and there is no hive at which dead-lettering it is the better outcome. The answer lane is now./render -> .and stays at home./colony/graphis drawable by a mutation — the one absolute endpoint that is. It addresses no cell but the colony's own read-only topology endpoint, and it is the sanctioned way to learn topology, because readingcolony.dbis forbidden. Refusing the lane protected nothing: it only meant a canvas had to be born with it, or somebody would go read the database instead./colony/mutations,/colony/traceand/colony/dead_lettersstay out of bounds.The result is that installing the shipped canvas is one line:
{"scope": "/org/acme/member/alice", "ctx": {}, "diff": {"add_nodes": [{"name": "canvy", "template": "canvy@0.1.0"}]}}No restart, no lane for the parent to grant, nothing pointing at it. Verified on a live 46-cell colony: the page answered over HTTP straight after the commit, with the full topology drawn from a store nobody fed — the timer's first tick asked
/colony/graphthrough the lane the mutation had just drawn.The same issue carried a second, nastier defect. A hive directory somebody copies in by hand was reported as unregistered for its children, but its
params.graphwas planned anyway — so every endpoint in it pointed at a child that was correctly not adopted, and the boot died onDanglingEndpoint. On every restart, until the directory was removed. Hives have no registry row (they are scope markers, not actors), so the reboot walk now consults the persistedhive_scopesfor them, the same way it consults the registry for cells.Database isolation has no exceptions left
The rule is that a cell touches only its own
cell.db— no other cell's, and notcolony.db, not even reading. One site was exempt: thevault's unlock attestation, which read the edge table to check that everything wired into it appears in its sealed contract before it accepts key material. The rationale was sound. The database read was not, and an exception on the books is a precedent, which is the expensive part (#160).It is gone. A cell that needs a fact about its own place in the graph declares it:
and receives a read-only handle at spawn that asks exactly one question — who points at me — answered by the authority that owns the edge table. Not the graph, not a scope, not its own outbound edges, never another cell's. No declaration, no handle. The defence is unchanged, because it never rested on the database: what protects a vault is the sealed contract in its own
cell.db, so a tampered edge is found whether it was read or told. Unverifiable still fails closed, and a vault stays LOCKED.meclaw --vault-addalso stops being a second writer: the offline user channel deliberately boots no colony and therefore never took the root lease, which left it writing the vault'scell.dbnext to the live cell that owns it. It now checks the lease and refuses while a colony holds the root.--vault-statusstays available, and--vault-revokekeeps working with a loud warning — being locked out of a vault must never be what stops somebody killing a leaked credential.A blocked colony says which mailbox
route()hands a message to a cell with anawait. That is correct — a full mailbox is backpressure, and dropping the message would be worse — but the waiter is the colony's own routing loop, so the whole colony stops. And it stopped silently: an empty dead-letter queue, nothing in the message log (the row is written after the send returns), no line naming the cell. Diagnosing that during #161 cost most of a day and ended with a SQLite client pointed atcolony.db.Now a pre-check at the call site logs the target, the sender, the trace and the configured capacity before the block, so the warning's timestamp is the start of the stall (#162). Semantics unchanged: a full mailbox still blocks.
4097 tests, 446 suites, both frozen routing corridors byte-identical. Full detail in the CHANGELOG.
All reactions