The verdict
The hardest part of unattended publishing is not generating an article. It is answering whether another run already published it. An activation flag or queue stored in an ignored local file can support a single-process demo. It cannot reliably arbitrate two workers, an interrupted process, or a production deployment whose receipt was never written.
Omnihex R1 keeps runtime state on automation/content-pipeline-state, a branch that is not connected to Pages deployment. It owns activation, candidates, runs, publication receipts, and the exact public manifest. It is not a second production branch.
What CAS means here
Git is not a database, but a constrained fast-forward push can act as a small compare-and-swap. A run reads state_head, calculates a claim, commits it, and pushes only from that old head. If another worker wins first, the remote head changes and the stale push is rejected. The correct response is to fetch, reread, and exit safely—not to force-push.
read state_head
-> claim candidate with run_id
-> commit
-> push old_head..new_head
-> rejected: another worker won; reconcile and stop
This is not a complete distributed lock. It relies on a normal Git remote, explicit identity fields, and a rule not to retry a rejected write. For “one worker owns this candidate,” those constraints are useful and inspectable.
Why several receipts exist
A candidate says what is being processed: logical ID, source hash, content hash, slug, and localized routes. A run says which states, sources, and QA checks occurred. A publication says which production SHA and live routes were released. A public-manifest answers what is public now.
If those objects are flattened into one log, recovery becomes ambiguous. If production succeeds but the publication receipt is missing, reconcile should compare the live SHA, content hash, and routes. Once the same candidate is proven live, it can write the missing receipt without publishing again.
Minimum idempotency keys
One run must not create another object for the same:
run_idcandidate_idlogical_content_idsource_hashorcontent_hashslug/locale- canonical route
- publication ID
These checks are not ceremony. They stop a retry from becoming a second article, another asset set, or another production deployment.
Keep the state branch out of deployment
The state branch should contain non-sensitive JSON and should not trigger a Pages Preview or production build. The source release remains bot worktree → main → validate → publish-production → production. State can be durable without making a draft public whenever a receipt changes.
That is why an exact public manifest matters. Before release, compute previous_public_set + exactly_one_candidate + deterministic_derived_routes, then compare it with the build output. A larger count is not enough; the system must know which URLs were added and ensure that drafts and unrelated routes did not enter.
Failure and recovery
If the state head moves, fetch, reread, and abandon the stale claim. If a lock is left behind, recover it only after its stale threshold and process absence are proven. If production succeeded but the receipt is missing, reconcile rather than publish again. If a live hard gate fails, preserve evidence and use the documented non-destructive rollback path.
Scope
Git-native state is a good fit for a low-frequency, auditable content publisher with a small candidate set. It is not a high-throughput queue or a cross-platform marketing database. External draft adapters may add their own receipts later, but the state branch should remain the sole state owner.
Evidence boundary
Git documents fast-forward pushes and linked worktrees. The CAS, receipt, manifest, and reconcile behavior described here comes from the Omnihex repository and its tests. It is an engineering case study, not a Git guarantee of distributed consistency.
