lichen.page.review from the reviewed point 0b92cb61 to stack eb5a1653, as one PR per subsystem (review set)

full 12: iroh: lichen-iroh folded in, each site process runs its own iroh #75

targeting full/11-ssg
Open opened by and assigned to notplants-bot.bsky.social
targeting full/11-ssg

Each site's iroh now runs in its own process: its endpoint, run by the site process's main runtime with the node key the front server sends it, its git sync with peers, its rooms served to peers directly, and its collaborators. What the endpoint needs of the hub it asks the admin thread, which alone holds the hub; the front server relays those asks and runs no iroh of its own. The separate lichen-iroh crate is gone: it was folded into lichen-site, its transport moved to lichen-server for SITE-FRONT-BOUNDARY, and FULL-SITE-PROCESS brought it back into lichen-site.


AST-verified changes

  • crates/lichen-iroh/src/** folded into lichen-site as src/iroh.rs and src/iroh/ (24 files; PER-SITE-PROCESS P2c-1, 20e9fa4c). Checked by notify-9a29b94c: "ast-checker rn6 at 8eef92b4..20e9fa4c ok (3538 items, 24 renamed, 217 carried, 0 visibility changes, 252 module declarations)"; adversary rerun "20e9fa4c equal=true 24-renamed 217-carried 0-vis" (lichen-adversary.md 11324). Allowed: lichen_iroh rewritten to lichen_site::iroh, and crate:: to crate::iroh:: inside the folded files.
  • The transport from lichen-site to lichen-server, verbatim (SITE-FRONT-BOUNDARY 10b1, 43e47f1a): AclGate with its ProtocolHandler impl and IrohSyncService with its impl from the site's iroh.rs to a new lichen-server/src/iroh.rs; iroh/{endpoint,git_transport,runtime,site_network}.rs to lichen-server/src/iroh/. Checked by notify-7dab54a2 on a rebuilt pure move (b754f831 → 71639fc0, which differs from the landed 43e47f1a by one #[cfg] line's placement): "AST-equal (4 moved, 6 files renamed carrying 67, 5140 stayed, plants caught)"; adversary rerun notify-ee68ddd8 "my checker equal; 4 items, 6 files, 67 carried". 10b1's changes follow in later commits.
  • ensure_iroh_identity, site_iroh_key and own_iroh_handle from the front server's features.rs to iroh_keys.rs (P2c-2a seam 5, e6415c2a). Run id not recorded: "move e6415c2a ok (1458 items, 3 moved, 0 visibility; plant on own_iroh_handle refused)" (lichen-builder.md 2347); adversary "equal=true 1458 items 3 moved 0 visibility". The three functions were written after 09-23, so the features.rs half is not in this diff (#31).
  • The path rewrites of SECURITY-FOLDER-AND-PRINCIPALS units 1 and 2 in this PR's files (crate::site_area → crate::admin_area, crate::access → crate::security::access, and the other security:: paths), which those checks cover (unit 1 notify-eebdd32e, unit 2 adversary notify-020eb199, both equal, errors 0), with the rustfmt rewraps after them (d6c25912, bdaa795b), proven by cargo fmt.
  • Not AST-checked: FULL-SITE-PROCESS 6f3b moved the transport back from lichen-server into lichen-site (iroh.rs → iroh/service.rs, iroh/git_transport.rs → iroh/git_sync.rs, iroh/runtime.rs rewritten as the site's runtime) with changes in the same reviewed diffs; no move record covers it.

Roughly 450 of this PR's 4,688 changed lines are code these moves carried verbatim. The rest is new: the 1,650-line git_transport.rs and 321-line runtime.rs of the old crate are deleted, and the site's iroh/git_sync.rs (627 lines) and iroh/runtime.rs (479) were rewritten for the hub and the admin thread, so they read as new code here.

On this forge the 5 renamed files here show as a whole deletion and a whole addition, so its diff reads 6,956 changed lines; with rename detection (git diff -M full/11-ssg full/12-iroh) it is 4,688.


At 09-23 each site's runtime ran its own iroh endpoint from the lichen-iroh crate, with its own copy of the site's git. Over the range:

  • The crate is folded, split, and brought back (PER-SITE-PROCESS P2c-1; SITE-FRONT-BOUNDARY unit 10b1; FULL-SITE-PROCESS 6f): SITE-FRONT-BOUNDARY gave the transport to the front server, with rooms bridged to the site's process; FULL-SITE-PROCESS gave it to each site's process. The front server's iroh.rs and iroh/git_transport.rs became the site's iroh/service.rs and iroh/git_sync.rs; its iroh/runtime.rs, iroh/bridge.rs, iroh/endpoint.rs and iroh/site_network.rs are deleted. All of them existed only inside this range, so this diff shows only the site's files.
  • The runtime (iroh/runtime.rs, 6f3b): started by the site process's main runtime where the server runs iroh, and ended with the process: an idle site's process stops, and its node with it. The endpoint uses iroh's N0 preset; its UDP, netlink route socket and name lookups are the site process's own, by its filter's iroh variant, and its TCP goes through the front server's egress.
  • The node key (site_process/node_key.rs, 6f2; lichen-server/src/iroh_keys.rs): the owner's, minted into the user record by the front server, which sends it once, right after the launch. The admin thread moves it to the main runtime's side and keeps no copy; the main runtime checks its public half against the node id the launch carried. Its bytes are zeroed on drop and never printed.
  • Git sync with a peer (iroh/git_sync.rs): a ref exchange, then packs over iroh-blobs. It runs when the hub's main moves, every 30 s with one peer in turn, and at start; each answer of a peer's is bounded to 60 s, and a whole exchange to 10 min. The main runtime runs no git: what it needs of the hub it asks the admin thread (site_process/iroh_hub.rs, 6f3a), through the front server, which relays those asks as an iroh-only identity admitted to nothing else. Only the hub's main is packed for a peer (git/peers.rs), and a peer's pack is taken only from a peer the hub's main lists, under every rule a fetch meets (git::inbound::take_a_peers_pack, #23).
  • Peers and collaborators come from the hub's main ([iroh].peers, collaborators.toml), read by the admin thread; a change restarts the endpoint. Collaborators' git remotes are fetched into the hub by the admin thread at start and when collaborators.toml changes.
  • Rooms are served from the site's own process (6f3b): the endpoint takes a peer's room stream, checks the room name against its grammar (peer_room_name, was bridged_room_name), and serves it from the site's rooms. The bounds the front server's bridge held are the site's now (protocol.rs): 16 streams per peer, 64 per site, 30 s for a stream's header. The bridge and the site's room-upgrade route are gone.
  • The site is told its peers' state, for the editor's peers panel (peers-changed, sync-sent).

Files

Site (crates/lichen-site/src/):

  • iroh.rs — the module list: runtime, service, git sync, rooms' protocol, collaborators, settings. Read this first.
  • iroh/service.rs (renamed from lichen-iroh/src/lib.rs) — the endpoint: the ACL gate and the three protocols on it.
  • iroh/runtime.rs — new: the site's runtime: peers, sync triggers, collaborators' remotes, rooms.
  • iroh/git_sync.rs — new: git sync between the hub and a peer, through the admin thread.
  • iroh/protocol.rs, iroh/stream.rs (renamed from lichen-iroh) — the room exchange, now with the per-peer and per-site bounds.
  • iroh/collaborators.rs, iroh/settings.rs (renamed from lichen-iroh) — parse text read from the hub.
  • git/peers.rs — new: the hub as its iroh peers see it.
  • site_process/iroh_hub.rs — new: the admin thread's hub routes for the endpoint.
  • site_process/node_key.rs — new: the node key in the process.
  • ipc/iroh.rs — the site's iroh peers and collaborators, as the front server changes them (the room upgrade and room feed are gone).

Front server (crates/lichen-server/src/):

  • iroh_keys.rs — new: the node key minted into the owner's user record, and the site's identity at setup.

The old crate: crates/lichen-iroh/Cargo.toml, src/endpoint.rs, src/git_transport.rs, src/runtime.rs — deleted.

Moved in: git/peers.rs, site_process/iroh_hub.rs and site_process/node_key.rs (new this round, placed with their subject, iroh).

Lives elsewhere

  • The hub, and git/hub_files.rs, which the peers are read with: #21. Taking a peer's pack and fetching collaborators' remotes (git/inbound.rs): #23.
  • The rooms themselves and their sync with files: #29.
  • The site process's start, which starts the endpoint on the main runtime and the admin thread beside it: #38. The control channel's NodeKey frame and the launch: #19.
  • The iroh routes' permission groups (lichen-site/src/acts.rs, access.rs's IROH): #19, #18.
  • lichen-server/Cargo.toml: #31. lichen-site/Cargo.toml: #37.
  • Tests (iroh/tests/*.rs, lichen-server's tests/iroh/, e2e) are in the base commit.

Category: iroh: lichen-iroh folded in, each site process runs its own iroh Size: 17 files, +2,410/−2,278 Rounds: round 0 at stack ae42e3c0; round 1 at 6b650b2a (SECURITY-FOLDER-AND-PRINCIPALS): path rewrites and rustfmt in iroh/git_transport.rs and iroh/runtime.rs; round 2 at b66397c0 (FULL-SITE-PROCESS 6f): the site's iroh moved from the front server into its own process: the endpoint and git sync are lichen-site's again (iroh/service.rs, iroh/git_sync.rs, iroh/runtime.rs; not AST-checked), the node key is sent at launch, the hub asks go to the admin thread (site_process/iroh_hub.rs, git/peers.rs), rooms are served without the bridge, and the front server's iroh files are deleted. Read this round in its interdiff: https://tangled.org/notplants-bot.bsky.social/lichen.page.october/pulls/28/round/2/interdiff Plans and ledger: FULL-SITE-PROCESS-2026-10-25.md (parts 4, 5, 7; units 6f1–6f3b); SITE-FRONT-BOUNDARY-2026-10-17.md (unit 1 item 2, unit 10: 10a, 10b1, 10b2, 10c; 11a1, 11e11), PER-SITE-PROCESS-2026-10-09.md (P2c-1 fold, P2c-2a seam 5, P3-5), OPERATOR-REVIEW-FIXES-2026-10-07.md U4 (N3: the identity made locally); lichen-builder.md 2326, 2347, 3477. Inline #[cfg(test)] modules: lichen-site/src/iroh/protocol.rs (tests, wire_property_tests, generation_tests). Seven more files point to a test file with #[path]. Bucket moves: none against round 1. As in round 1, lichen-site/src/ipc/iroh.rs is here rather than with the site process. The transport kept this PR through both of its moves. Round 1: #9 (iroh, sync and rooms) covered these files from 0b92cb61; the deleted lichen-iroh files and the files new this round are new to the set.

This pull request has no versions submitted yet.