Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Review: Peer serving & the fleet

Review of the layer as described, under the sovereignty litmus. Verdicts cite xenon-launcher main @56e94575; gap IDs (G1, G2, G5) are this beat’s register and feed Part IV. The identity-side gaps G3/G4 are held in the transport review.

The headline

The serving path is membership-blind. Authentication is a 32-byte bearer secret in a ticket file, while a fully built, signed, revocation-capable membership plane sits unwired one crate away. The sovereign “device group” story and the serving story are not yet the same graph — a device removed from the group keeps serving and consuming for as long as it holds a live ticket. Everything else in this review is downstream of that one honest sentence.

What the layer does well, it does with unusual care: fresh secret per session, constant-time comparison, 0600/DACL ticket custody, digest-pinned catalog indexes that never overwrite last-good on mismatch, honest liveness states, and hash-chained audit records on both publish and verify. The craftsmanship is real; the open question is the authorization model, not the plumbing.

Desired vs current

Want (decisions / packets)Have (code @56e94575)Delta
Peer topology, every platform a full peer (P-206)Windows publish+consume native (P-206, PR#62); macOS proven (P-208)Auth is bearer-secret, not the membership plane that already exists — the two graphs are unjoined (G4).
Litmus: fork permissions · auditable · exit without lossCatalog + index publication hash-chain audited; liveness inspectable; tickets 0600/DACLRoute secret has no revocation list, epoch, or bounded lifetime (P-209 STATE). “Fork permissions” for a served origin = restart the publisher — blunt.
Preserve restart-as-revocation until a real revocation story exists (P-209 follow-on)Exactly implemented: fresh secret per session, durable reuse refused (peer_serve.rs:428)A correct stop, not a design. --rotate-secret is inert scaffolding awaiting the G1 decision.
Browser → plane (5454) → internal forward (5198); plane owns Host normalization (d/100, d/102)Consumer rewrites upstream Host from ticket origin_port (P-209 item 4)The runtime seam where the plane owns Host normalization is still queued (d/102 follow-up seam).

Gap register (this beat — serving slice)

G1 — Route-secret revocation / lifetime (primary)

Exists: a fresh 32-byte secret per publish session; no persistence, no revocation list, no epoch, no expiry (peer_serve.rs:428-433; P-209 STATE is explicit that persisting would remove restart-as-revocation on a route with none of those).

Why this needs design: restart-as-revocation is all-or-nothing — any publisher restart strands every consumer — and durable secrets are blocked because no finer-grained revocation exists. The layer is boxed in until this is decided.

Options: (a) bounded-lifetime ticket (exp field + refresh) — cheap, bounds exposure, still bearer; (b) per-consumer secret + a revocation epoch/list in the published index — real per-peer revocation, needs a distribution channel; (c) bind serving to existing group membership so group revoke already cuts the tunnel (reuses MembershipRegistry; collapses G1 into G4); (d) UCAN capabilities with exp + revocation (below).

Decides: Luke — litmus- and custody-touching, effectively irreversible once tickets are in the wild.

G2 — Windows exposure-tripwire asymmetry

Exists: on Unix, opening an over-shared ticket refuses with a chmod 600 instruction (peer_serve.rs:295-302); on Windows, the same condition is silently repaired — the ACL is narrowed and reading proceeds (:308-323).

Why this needs design: refusal is a tripwire — “something widened access to your credential” is a signal the operator should see. Repair hides it. P-206 queued exactly this (“repair-vs-reject asymmetry”).

Options: (a) refuse by default on a non-owner ACE, with an explicit --repair opt-in (Unix-symmetric); (b) refuse + audit the observed ACL; (c) keep repair but emit a loud audit record.

Decides: Fable (reversible, low blast radius) with a custody re-review — but it wants a taste call.

G5 — Ticket distribution channel

Exists: publish prints only ticket_path= (peer_serve.rs:463); the operator moves the file out of band. No in-product handoff exists.

Why this needs design: the bearer secret’s entire security rests on the transfer channel — which is undefined. Custody is meticulous at both endpoints and unspecified in the middle.

Options: (a) deliver tickets over the already-authenticated group gossip lane (member→member, in-band, encrypted); (b) QR handoff reusing the invite QR machinery; (c) keep out-of-band and document the threat model honestly.

Decides: Luke/Jan — UX + custody. Note: G4 option (a) + G1 option (c) dissolve this gap for the member-to-member case entirely.

The UCAN question

What is UCAN? UCAN (User-Controlled Authorization Networks) is a capability token format: a signed JWT-like token where the issuer (iss) and audience (aud) are keys expressed as did:key, carrying attenuable capabilities, expiry (exp), and delegation proof chains (prf).

A UCAN-ified ticket would replace the opaque bearer secret with a signed capability: iss = publisher key, aud = consumer key (device keys are already Ed25519, so did:key is free), att = {with: "xe://<origin_id>/<app>", can: "serve/consume"}, plus exp and caveats.

Gives: audience-binding (only the named consumer key can present it — removes the pure-bearer exposure at the heart of G1/G5); bounded lifetime for free; delegation chains with attenuation (publisher → consumer → sub-share); per-app/per-port caveats; a revocation-by-CID story.

Costs: DID resolution + signature verification per session (vs one constant-time compare); an Xe resource namespace and capability semantics must be defined; revocation still needs a distribution channel; net-new machinery.

The tension worth naming: the group membership plane is already a capability system — a signed document says who may connect, and revocation closes live connections. Adopting UCAN for serving would duplicate much of crates/net/group. Verdict this review offers the session: gate serving on the existing membership plane first (G4 option a); reserve UCAN for the one thing membership cannot express — delegation to a non-member — and decide unify-vs-bolt-on before adopting any of it.

Sovereignty litmus check

CriterionVerdict for this layer
Inspect what it seesHolds. Liveness states map 1:1 to observations; path receipts printed per tunnel; the 503 for offline peers even admits what it cannot override (a service-worker cache).
Fork permissionsWeakest point. One secret per publisher session — no per-consumer grant, attenuation, or revoke. The only permission change is restarting the world. (G1)
BYO models + keysPartial. Keys are local; relays configurable but unsigned on this plane (G3, transport review).
Movable memoryPartial. Catalog indexes are cached, digest-pinned, and survive publisher outage (last-good rule) — the view moves; app data itself is single-homed (site-wide, Part IV).
Auditable actionsHolds for the catalog (hash-chained publish/verify records). Fails for handoff: ticket distribution is out-of-band and leaves no record (G5).
Exit without lossConsumer: yes — remove the peer, keep your data. Publisher restart strands all consumers until tickets are re-carried (G1) — availability loss, not data loss.

Questions for the Luke + Jan session

  1. Unify serving with membership, or keep bearer + add UCAN? (G1+G4+G5) Gating the serve ALPN on the existing MembershipRegistry reuses built code and yields real revocation for free; UCAN is heavier and partly duplicates the group plane. Which spine?
  2. Route-secret lifetime — adopt a bounded-lifetime ticket (exp) now to unblock durable secrets, or wait for full membership gating? (P-209 explicitly parked durable secrets on this.)
  3. Windows tripwire — refuse-by-default on a non-owner ACE (Unix-symmetric) with --repair opt-in, or keep silent repair + loud audit? (G2 — reversible, but wants a taste call.)