Reading copy of lichen.page.review: one PR per unit, product changes only

OCTOBER-REVIEW-REVISIONS unit 5: tests come home, seams go, one slot per site #69

targeting base/october-review-revisions-unit-5 from view/october-review-revisions-unit-5
Open opened by and assigned to notplants-bot.bsky.social
targeting base/october-review-revisions-unit-5 from view/october-review-revisions-unit-5

Tests come home, seams go, owners simplify and per-site state becomes one slot.

  • lichen-site's tests move next to their code and all 24 pub use lichen_site::… re-exports in lichen-server are removed; 22 wrapper items only the moved tests used are deleted.
  • The eleven seam traits and PublishOpener are inlined into their single shipped implementations (MainCalls stays, as two implementations ship); site_seams.rs and git/seams.rs are gone.
  • SiteOwner is one plain type (atproto_did, deploy_key_public), the main runtime holds no handle, and a handle is derived from the DID only when verified both ways (new identity resolver with SSRF guard and a TCP-only DNS resolver); old pds://<handle>/… remotes are pushed only when the handle verifies.
  • Per-site maps become each site's own state behind an Arc, the runtime registry is a single slot, SiteHost is inlined, and domain parameters drop from 75 to 33.

OCTOBER-REVIEW-REVISIONS, unit 5 (subunits 5a, 5b, 5c, 5d combined, replacing their per-subunit PRs). Plan: https://tangled.org/notplants-bot.bsky.social/lichen-orchestrator/blob/main/machine-docs/plans/OCTOBER-REVIEW-REVISIONS-2026-10-28.md

This is a reading copy: only this PR's product changes, applied in order on its base. Nothing here is to be merged.

Source PRs on lichen.page.review (product), in order, with their original descriptions #

  • #3406 s/774-orr-u5a-tests-home — ORR 5a: lichen-site's tests come home where a move can; the lichen_site re-exports go

    OCTOBER-REVIEW-REVISIONS unit 5a, product: lichen-site's tests come home where a move can bring them (C2). The product side of the move:

    • #[cfg(test)] #[path = "tests/…"] mod tests; includes in lichen-site's source files, for the tests that moved beside their code.
    • All 24 pub use lichen_site::… re-exports in lichen-server go, with those that passed lichen-site items on (git, publish, token, users, lib.rs's SiteRecord and HUB_CHECK). Callers in lichen-server, lichen-cli and lichen-tauri name lichen-site directly. The 23 pub(crate) forwarders in lichen-server's own src are outside the plan's 24 and stay.
    • What becomes cfg(test): hooks used only by tests that came home (hub_repo's staging count, staged/staging_takes, inbound::forget). hub_repo's for_tests is cfg(any(test, test-support)), since lichen-site's own tests now use it too.
    • What stays on test-support: the outbound, inbound, rewrite and publish-run hooks, is_opened, and each for_tests module, because lichen-server's remaining tests still drive them.
    • 22 wrapper items that only the moved tests used are removed.
  • #3408 s/776-orr-u5b-no-seams — ORR 5b: no seams (inlined, deleted, or one kept with its reason)

    OCTOBER-REVIEW-REVISIONS unit 5b, product: no seams (C1). The 11 seam traits and PublishOpener go, but for one kept with a reason.

    • Inlined into their one shipped implementation:
      • StorageBudget → OwnBudget in site_process/admin.rs;
      • WeightChanged → TellTheFront in link.rs (the front's FrontWeight becomes allowance::changed);
      • PublishTold, OwnerCredentials, Owners (OwnOwner), Sites (the routes take OwnSite);
      • PublishOpener (the publish takes a PublishSite).
    • Deleted: FirstStart, Handoff and Handed, whose only shipped implementations were no-ops. MainMoved and ToItsRemote become direct outbound::moved calls.
    • Kept, named for what it does: MainCalls, since two implementations ship and both are used through it (OwnMain and ThenTheHub). It moves to git/hub.rs.
    • Data types to their users:
      • SiteArea → admin_area.rs;
      • FIRST_START → hub_repo.rs;
      • SiteFacts and SiteHandle → git.rs;
      • RESTARTING → site_process/admin.rs;
      • what is left of asks.rs → acts/asks.rs, beside the router most of its asks name.
    • Files gone: site_seams.rs and git/seams.rs. lichen-server's front_seams.rs keeps only its shipped forwarding (no traits, no stand-ins) until unit 6 moves it to forwarder/.
    • Not in this unit: SiteHost, which unit 5d (one site, one slot) changes.
  • #3410 s/778-orr-u5c-site-owner-did — ORR 5c: SiteOwner is one plain type; a handle only verified both ways; DID-form remotes

    OCTOBER-REVIEW-REVISIONS unit 5c, product: SiteOwner is one plain type, and a handle comes from the DID only when it is verified both ways (C3, R6).

    • SiteOwner { atproto_did, deploy_key_public } in lichen-site/src/owner.rs, where OwnerFacts was; unit 6 moves it to ipc/site_owner.rs. Gone:

      • the SiteOwner trait and LinkOwner;
      • AuthProvider from lichen-site (it stays in lichen-server's users.rs);
      • link::owner_facts, has_remote, should_push, start_iroh_side;
      • the handle in the launch, in LaunchIroh and in the lent session.

      The main runtime holds no handle.

    • The resolver moves to lichen-site/src/atproto/identity.rs, with its SSRF guard. Its commit is a move: the AST check matched all 20 moved items, and its one difference is a // comment above client.rs's use lines rewritten inside that commit.

    • New in identity.rs: names_both_ways, verified_handle, and a TCP-only DNS resolver at 127.0.0.1:53, since a confined site with iroh off has no /etc/resolv.conf. The admin thread's fetches go through the site's egress.

    • Remotes:

      • An old pds://<handle>/<domain> remote is pushed only when its handle verifies both ways to the owner's DID. Git is given the DID form per push (-c url.pds://<did>/….insteadOf=…), and the owner's URL is never rewritten.
      • A handle that names another DID becomes a proposal: "not pushed: this handle no longer names your account".
      • A check that fails on the network is not a refusal and not a proposal: "not pushed: the handle could not be checked (network); it is tried again on the next push".
      • New remotes and PDS site records are written in DID form; an import reads either.
    • iroh: collaborator entries stay handles; the site's own entry is recorded by the admin thread.

    • The git-remote-pds pin moves to the fork's 6e0847f2 (notplants.net/git-remote-pds #14: the helper takes a DID-form URL). It changes in Cargo.toml, Cargo.lock, the flake hash and the submodule link.

  • #3412 s/780-orr-u5d-one-slot — ORR 5d: one site, one slot; the per-site maps become the site's own state

    OCTOBER-REVIEW-REVISIONS unit 5d, product: one site, one slot (C4).

    • The per-site maps become each site's own state behind an Arc every clone shares. That covers outbound's, inbound's, the hub's and hub_repo's maps and locks.
      • WRITERS is deleted: shipped code took only its read side, and a deletion waits for the process.
      • The rewrite hold is a SiteRuntime field.
      • Publishes no longer holds a map.
    • Kept as maps, each with its reason in the structure test:
      • STATES (keyed by hold id);
      • the build caches (lichen server build builds every site in one process);
      • the frontend's UPDATES (not on the plan's list);
      • the probe's SEEN;
      • DUE in git/hub.rs. Making it a field would thread the runtime through 13 shipped and about 30 test callers of the commit helpers. Say if it should be converted.
    • The runtime registry is a single slot with no domain. SiteHost had one implementation and is inlined into SiteProcessHost; host.rs goes.
    • Dead code removed: site_record, retire, runtime_lock_is_held, the Weak registry, the three forgets, is_opened, outbound::rewritten.
    • domain parameters: 75 shipped go to 33. The 42 removed were only keys; the 33 left name the site (DNS, the PDS repository, known hosts, logs).
    • The test hooks at outbound.rs and publish/run.rs stay on test-support, since lichen-server's tests still drive them.
    • From 5c's note: well_known_did reads at most 2 KiB. A longer body is a definite "no DID", because the host did answer.

Commits #

  • 65d48fe8b OCTOBER-REVIEW-REVISIONS unit 5: subunit 5a
  • 640ba1634 OCTOBER-REVIEW-REVISIONS unit 5: subunit 5b
  • 56a58bf14 OCTOBER-REVIEW-REVISIONS unit 5: subunit 5c
  • 6bbb356fb OCTOBER-REVIEW-REVISIONS unit 5: subunit 5d

Count and shas #

count-product-code-lines e48510ca45df..6bbb356fb4f7: NET -744 · counted +1709 -2453 · moved out of the counted set +0 · comment-only deletions flagged 136 · macros flagged 0 · tests-folder code flagged 0

Base e48510ca45df9d6c17c871f0b1e6d881a95b700c (tip of s/773-orr-u3c-invariant-tests). Head 6bbb356fb4f7f3d0d5c8433d92d5e9d29be408b3. 94 files changed.

Check #

Files that differ from s/780-orr-u5d-one-slot (later tests PRs or merges touched them, or the diff was resolved): crates/lichen-server/src/admin_area.rs, crates/lichen-server/src/features.rs, crates/lichen-server/src/lib.rs, crates/lichen-site/src/atproto/tests/identity.rs.

Files that a tests PR of this unit also changed (so a test-only edit could in principle sit in them): crates/lichen-server/src/admin_area.rs, crates/lichen-server/src/features.rs, crates/lichen-server/src/lib.rs, crates/lichen-site/src/atproto/tests/identity.rs.

Commits 0