Repeatable operator procedures, how to recover from a bad release, and where to look when something fails. Local fixture work needs none of this; live operations need the maintainer's separately scoped authority.
| Reference | Value |
|---|---|
| Subject | Publishing, image mirrors, schema and permission operations, rollback and recovery, credential rotation, observability; for operators |
| Verified source | apps/cms/scripts, cms.yml, apps/cms/README.md on main at f40e8704, checked 2026-11-07; image publishing, the article editor deployment and permission lanes re-verified on main at 0461e045 (apps/cms/README.md, build-media.ts, cms.yml), checked 2026-11-10 |
| Support state | Publishing procedures checked against main f40e8704. Production builds read live CMS content; provider operations and approval receipts have their own evidence |
build_queue), Flows, Publish site, and confirm once.| Feedback | Meaning |
|---|---|
| Updated | The public version changed between reads; this request is not proven to be its cause |
| Not updated | The two readable versions match; a slow build may complete after the check |
| Could not verify | A version read or script failed; inspect Vercel before retrying |
| Hook rejected | Immediate dedicated notification; the normal wait is bypassed |
Saving CMS content does not itself start a build. A production build uses live CMS content, whether triggered by Publish site or a merge to main. A merge after a CMS content write therefore publishes that content when the production build succeeds; the code diff does not bound the content published. Each successful hook path makes two public JSON reads, one hook POST and one notification. The wait is in memory, not a durable queue; restarting the CMS loses that notice. A stalled Request has no per-operation timeout. Flow links must be unique separately within resolve and reject columns, including across flows; each failure path owns its own notice.
Source: flows.json, operations.json. ‣ owns the dated successful version-pair and notification receipt, plus unobserved error/overlap scenarios.
Upload the image in Directus, reference it in published content, then run Publish site. The production build publishes each referenced PNG, JPEG, WebP, GIF or AVIF to /images/cms/; no manifest, ID map or code PR is needed. For a theme pair in an image block, pick the light file under Light version in the Article Block Editor, or upload example.dark.png and example.light.png and select only the dark file. Review file contents, placement and any pair before publishing. A missing, unreadable or invalid image fails the build and the last successful site keeps serving. Build Bot reads only files in the seven delivery folders (about, blog, brand, illustrations, og, projects, services) or unfiled.
A committed mirror is optional reviewed pinning and the only path for a new SVG. To pin one:
fixtures/assets-manifest.json and the UUID map through the reviewed asset workflow.# in apps/cms
bun scripts/mirror-asset.ts --path=images/about/headshot.webp
bun scripts/mirror-asset.ts --path=images/about/headshot.webp --apply-sha256=<reviewed-digest>
sha256 in fixtures/assets-manifest.json to the reviewed digest and commit it with the new bytes. The script doesn't change the manifest, and the export fails on a digest mismatch.The script reads one file and writes local bytes only. It fails before replacing anything on an unregistered path, an invalid image, a format mismatch or a changed digest. Deleting a file in the CMS does not remove committed or deployed bytes; removing a committed mirror is its own reviewed code change. A deleted upload that published content still references fails the next live build.