R1 — Atomic Chain Writer
R1 is the substrate that holds the rest of the framework up. Every audit row written to a state machine's entangled state goes through this writer. Its job is to guarantee that no two writers can ever produce an entangled state break under concurrency, even when many processes are racing to append the next row.
Why it exists
The entangled state is a singly-linked hash list:
rowHash(N) = sha256(`${zeqondNumber}|${stateHash}|${prevHash}`)
prev_hash[N+1] = rowHash(N)
Without serialisation, two writers can both read the same head, both compute
prev_hash against it, and both insert a row claiming the same logical
timestamp. The entangled state branches. Every downstream verifier disagrees.
The previous implementation cached the entangled state head in a JavaScript Map<originId, string> per process. Two writers reading the cache concurrently
both saw the same head, both wrote with the same prev_hash, and the entangled state
silently diverged. The legacy break at row 15053 on zeq07792026349 was
the visible symptom.
What R1 ships
Postgres advisory lock per origin. Every append acquires
pg_advisory_xact_lock(hashtext(origin_id)) at the start of the
transaction. Concurrent writers on the same entangled state block at this line until
the prior transaction commits.
await tx.execute(sql`SELECT pg_advisory_xact_lock(hashtext(${args.originId}))`);
SELECT-latest inside the same transaction. Once the lock is held, the writer reads the current head row from the database — never a JS cache.
const [last] = await tx
.select({ zeqondNumber, stateHash, prevHash })
.from(auditLogTable)
.where(eq(auditLogTable.originId, args.originId))
.orderBy(desc(auditLogTable.zeqondNumber))
.limit(1);
Bigint conversion. node-postgres returns bigint columns as JS
strings by default. The writer explicitly converts before any arithmetic:
const lastZ: bigint | null = last ? BigInt(String(last.zeqondNumber)) : null;
Without this, lastZ + 1n against a string throws Cannot mix BigInt and
other types silently inside the catch — the retry hits the same error,
and the per-machine ticker swallows the rejection.
UNIQUE INDEX defence in depth. Even if every other guard fails, the
database refuses to accept a duplicate logical timestamp on the same entangled state:
CREATE UNIQUE INDEX audit_log_origin_zeqond_uq
ON audit_log (origin_id, zeqond_number);
The writer also includes an optimistic-zeqond-bump retry: if the proposed
zeqond is already taken, bump to last.zeqond + 1 and retry up to five
times. With the advisory lock in place this branch is cold but kept as
defence-in-depth.
The JS heads cache is gone. Every write reads the canonical head from the database inside the transaction. Postgres is the source of truth.
Stress verification
Two stress rounds against a live chain (zeq07792026349) post-deploy:
| Round | Concurrent writes | Organic ticks | Chain state |
|---|---|---|---|
| 1 | 8 | 15 | HEALTHY (0 broken links) |
| 2 | 20 | 15 | HEALTHY (0 broken links) |
79 rows added across both rounds, zero cannot mix BigInt errors in the
writer log, chain-repair.mjs reports chain is healthy — no rows updated after each round.
File map
shared/api-core/src/lib/auditLog.ts— atomic writershared/api-core/migrations/20260428_chain_invariant.sql—UNIQUE INDEXapps/zeq-dev/scripts/chain-repair.mjs— forward-relink repair tool
What this enables
R1 is the load-bearing piece for everything above it:
- R2 awareness — validates the trailing 1024-row window after each tick; only meaningful if the writer guarantees no concurrent corruption.
- R3 phase-locked cipher — devices encrypt payloads keyed on
(zeqond, originId); nonce reuse is impossible because the UNIQUE INDEX prevents a second row from sharing the same zeqond on the same origin. - HZC archiver — continuity proofs assume the entangled state has no internal branches.
- ZeqCompliance v1 — every envelope's zeqond ties to exactly one row.
Try it
Spin up an entangled state, post events concurrently, and inspect:
# 8 concurrent prove writes
for i in $(seq 1 8); do
curl -s -X POST https://zeqapi.com/api/chain/<your-slug>/event \
-H "Authorization: Bearer zsm_..." \
-H "Content-Type: application/json" \
-d "{\"transitionId\":\"stress-$i\",\"transitionType\":\"compute\",\"stateHash\":\"0x$(openssl rand -hex 32)\"}" &
done
wait
# Validate the chain
node --env-file=.env scripts/chain-repair.mjs <your-slug>
# → "chain is healthy — no rows updated"