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

ONE-RUN-MODE (whole) #89

targeting base/one-run-mode-whole from view/one-run-mode-whole
Open opened by and assigned to notplants-bot.bsky.social
targeting base/one-run-mode-whole from view/one-run-mode-whole

Each mode decision is made once. A single site runs as a server with one site, "unsandboxed" is one switch, and the duplicate start and build paths are gone.

A single site is a server with one site. One handler per admin act (TargetSite, git_failed) answers a single site's rewrites under /cms on the site its host serves; the three single-site copies go. A single site has no edit host: its edit.<site> name no longer picks the edit session layer, and is no longer approved for a certificate (/tls-check approves the public_url domain alone). serve_single_background, which nothing started, SiteServerSettings::is_single_site, which nothing read, and ServerSettings::confined() go.

One switch for the sandbox. lichen_sandbox::config::use_sandbox() is fixed once per process, where its mode is known: a site process's by its admin thread as it reads the launch, before any start hook. The front's repeated ensure_enforceable goes, and its guidance is in the switch's refusal. Off Linux the switch is off and asking for it fails closed, naming the platform; a single site's and the desktop's are off too. confined() folds into use_sandbox.

One way to start and build. A single site starts as a multi-site's does, its site process building it; the front writes only a missing folder's starter. Offline build and export are one each, and core's prepare_site goes. A single site's settings file is read once at start, for the check, the copy and the warning, and the two retired keys are one table, each warned of.

The desktop has no dashboard domain, so three reads test the domain alone (the role headers, the cookie's own-host rule, the edit host's handoff), and edit_on_edit_host goes.

Kept on purpose. dashboard_guest_site still answers none on a single site, because it decides admission there; the login form's named-site refusal and the git token's owner check stay because their redundancy was not proved. Every other single-site and desktop read is a real difference.


ONE-RUN-MODE, the whole phase in one reading PR. Plan: https://tangled.org/notplants-bot.bsky.social/lichen-orchestrator/blob/main/machine-docs/plans/ONE-RUN-MODE-2026-10-28.md

Only the phase's Rust product code is here: every .rs file under crates/<crate>/src/ (no tests folder in its path), which is what e2e/ci/count_product_code_lines.py counts as product. The head is the base plus one commit that sets each of those files to its content at the end tip (added, changed, deleted and renamed files alike). Tests, docs, scripts and non-Rust files (including Cargo.toml and Cargo.lock) are not in it, so the crates here are not meant to build on their own. Reading copy; nothing here is to be merged.

Source PRs on lichen.page.review (product), in order #

  • #3809 a single site as a server with one site (ONE-RUN-MODE unit 1)
  • #3813 "unsandboxed" is one switch (unit 2)
  • #3815 the duplicate start and build paths (unit 3)
  • #3817 the desktop's reads (unit 4)
  • #3821 the close's repair, on unit 5's docs (#3819)

Product commits from other work on stack, in this range #

Not ONE-RUN-MODE's own, but on stack between the base and the end tip, so in this diff: the terminal commit polling interval carried with the site's launch instead of fixed (a77bbccca, with 975c91e39, 5af220710, f6be7eee5, ca7ad0a8e, 9e5dabe80 and bc491df43).

Base, end tip, count #

Base 288bf24c8e7ed28c8296f6b7bb4d59d08ac0147d. End tip fa06c1d3a22193c8f6227c7fe394d7ce8c5f69f5. Head 25ece51ebed14f3c79ebc3d522e1565b9a0c518a (27 files: 26 added or changed, 1 deleted).

Counter, base to end tip (the phase as lichen.page.review has it):

count-product-code-lines 288bf24c8e7e..fa06c1d3a221: NET -117 · counted +142 -261 · moved out of the counted set +2 · comment-only deletions flagged 13 · macros flagged 0 · tests-folder code flagged 0

Counter, base to head (this PR):

count-product-code-lines 288bf24c8e7e..25ece51ebed1: NET -119 · counted +142 -261 · moved out of the counted set +0 · comment-only deletions flagged 13 · macros flagged 0 · tests-folder code flagged 0

The two are equal in every Rust line. They differ only by two lines outside the Rust files that the counter reads from the end tip: lichen-ts/scripts/throwaway-lichen.mjs, as moved out of the counted set (+2). That file is not in this PR.

Check #

git diff base head lists only counter-product Rust files, and the head's content equals the end tip's for each of them. For the counter, the head's counted and NET lines equal the end tip's once those non-Rust lines are taken out.

Record #

ONE-RUN-MODE is COMPLETE at stack fa06c1d3a22193c8f6227c7fe394d7ce8c5f69f5 (coordination report machine-docs/reports/ONE-RUN-MODE-2026-11-11.md). Unit 5's docs are not in this PR.

Commits 0