superseded by the full set from 09-23, #17–#37
description:
Review set for lichen.page.review, 0b92cb61 (reviewed) → eb5a1653 (stack). PR 7 of 16. 23 files, +3951/−1662. One commit, 887f24d9fda8, which sets these files to their content at eb5a1653. Targets #6 (oct/06-git-sync). #8 stacks on this one. Tests and generated files are not in any PR; they are in main.
The front server publishes; the site only builds (SITE-FRONT-BOUNDARY decision 10, unit 9). The site holds no deployment credential and no atproto session any more.
A publish now runs like this (one function, publish::run, for the editor's Publish, the dashboard's, and a save with auto_publish):
- The front server checks the caller may publish, takes the site's publish lock, and asks the site for its publish build. The site commits what is saved, builds
distwith the standard.site links already in it (the record keys are known before the build), writes a manifest of the records it wants, and pushesmainand a parentlessrefs/dist/latestcommit of the build into the hub. - The front server then does each step with its own credentials, whatever the step before did (operator note N4): writes the standard.site records from the manifest, after checking it; pushes the source if
push_on_publish; deploysrefs/dist/latestto GitHub Pages, Codeberg Pages or wisp.place. The front server never runs anything fromdist. - The report keeps the
PublicationReportshape, now with one outcome per destination (publication.rs), and the publish record lives in the site's area.
The records check is strict: the front server's own record of the site's keys is the authority; only records of this site's publication are written or deleted (several sites share one PDS); new keys use createRecord, which never replaces a record. The site's GitHub/Codeberg/wisp publishers are deleted.
info:
Plans: SITE-FRONT-BOUNDARY-2026-10-17.md ("Publishing", decision 10, unit 9a deployment, 9b records), SITE-FRONT-BOUNDARY-U9-DESIGN-2026-10-23.md (§4, §9, §11, §12); OPERATOR-REVIEW-REVISIONS-2026-10-13.md N4 (explicit destinations, best-effort reports).
Files
Front server:
crates/lichen-server/src/publish/run.rs— new: the one publish path, its lock, the build ask, then the steps. Read first.crates/lichen-server/src/publish/records.rs— new (1068 lines): the record of keys (standard-site.jsonin the area), its migration, the manifest check, writing and sweeping records. The diff-and-sync code moved here from the site'sstandard_site/publish.rs.crates/lichen-server/src/publish/records/remote.rs— moved fromlichen-site/src/publish/standard_site/remote.rs: remote inventories; a publication is this site's only when the front server's record holds it.crates/lichen-server/src/git/deploy.rs— new: deployrefs/dist/latest: a parentless commit with the domain file pushed from the hub to Pages (no owner credential: the target is the site's to write), or wisp.crates/lichen-server/src/site_area/publish.rs— new: the publish record, the Pages deploy key and wisp's credential, in the area; no route answers the key or the credential.crates/lichen-server/src/publish.rs— module list.
Site:
crates/lichen-site/src/git/publish_build.rs— new: the site's half: commit, build with records,dist_commit(links resolved to bytes; a link outside the site refuses), push both refs.crates/lichen-site/src/publish/standard_site/manifest.rs— new: what the build asks of the records.crates/lichen-site/src/publish/standard_site.rs,standard_site/publish.rs(−831),identity.rs,types.rs— the site keeps discovery, keys and the manifest; writing moved out.crates/lichen-site/src/publication.rs— new: the per-destination report (N4).crates/lichen-site/src/publish_record.rs— the record's format and rule, now written by the front server.crates/lichen-site/src/publish.rs,publish/router.rs,publish/helpers.rs(−166),publish/settings.rs— settings and the "is publishing configured" route kept; target checks kept for the front server's use.crates/lichen-site/src/publish/github_pages.rs,codeberg_pages.rs,wisp.rs,api/publish.rs— deleted.crates/lichen-site/src/atproto/pds.rs—create_record, which the PDS refuses where a record exists.
Moved in (from where the starting map put them): git/deploy.rs and git/publish_build.rs (Git), site_area/publish.rs (Site area), atproto/pds.rs (iroh/sync, by its atproto path) and publication.rs (site core). Each is a step of a publish.
Lives elsewhere
- The build itself (the rebuild lane, scripts, SSGs): #8. The source push used by
push_on_publish:git/outbound.rsin #6. - The dashboard's
trigger-publishroute:api.rsin #11. The owner's session the records use:credentials.rsin #10. - Tests (
publish__records.rs,publish__run.rs, standard_site tests, e2e publish tests) are inmain.