Home Contact
Universal Substratev1.4
/
For agents Markdown

34. Reference ledger engine, concurrency, partitioning, and retention

A conforming ledger can be implemented with different storage products, but the reference profile uses PostgreSQL because unique constraints, transactional row locks, serializable transactions and an atomic outbox can enforce the write invariants directly.…

Concept & directionLNK

A conforming ledger can be implemented with different storage products, but the reference profile uses PostgreSQL because unique constraints, transactional row locks, serializable transactions and an atomic outbox can enforce the write invariants directly. The broker, graph, search, feed and telemetry stores remain disposable projections.

#34.1 Ordering model and cursors

OrderGuaranteeConsumer contract
streamSequenceGap-free uint64 inside one tenant+streamOptimistic concurrency and aggregate replay
shardPositionGap-free uint64 inside one logical shard epochCanonical event delivery, projection checkpoint, and receipt chain
recordedAtStore UTC instant; may tie and is not an ordering keyBitemporal filtering and operations
recordIdTime-ordered UUIDv7 for locality onlyOpaque identity; never authoritative ordering
checkpoint vectorMap logical shard epoch -> inclusive commitSequenceConsistent multi-shard projection watermark
public cursorAuthenticated-encrypted token or random server handle bound to query, audience, policy and checkpoint vectorStable pagination; expires but never silently changes scope
Table
There is no universal global sequence
Cross-shard order is a partial order expressed through recorded causality, transaction/saga relations and a checkpoint vector. Fabricating one global counter creates a hot lock and a false temporal claim.

#34.2 Reference relational schema

Table
PostgreSQL reference DDL - compact v1.4 skeleton
CREATE TABLE stream_head (
  tenant_id uuid, stream_id uuid, logical_shard_id text,
  last_sequence bigint CHECK(last_sequence>=0), last_record_digest bytea,
  writer_epoch bigint CHECK(writer_epoch>=0),
  PRIMARY KEY(tenant_id,stream_id));

CREATE TABLE shard_head (
  ledger_id uuid, tenant_id uuid, logical_shard_id text, chain_epoch bigint,
  last_commit_sequence bigint CHECK(last_commit_sequence>=0),
  last_receipt_digest bytea NOT NULL, publisher_epoch bigint,
  shard_map_version text,
  PRIMARY KEY(ledger_id,tenant_id,logical_shard_id,chain_epoch));

CREATE TABLE record_ledger (
  ledger_id uuid, tenant_id uuid, logical_shard_id text, chain_epoch bigint,
  commit_sequence bigint CHECK(commit_sequence>0), stream_id uuid,
  stream_sequence bigint, record_id uuid, canonical_bytes bytea,
  record_digest bytea,
  PRIMARY KEY(ledger_id,tenant_id,logical_shard_id,chain_epoch,commit_sequence),
  UNIQUE(tenant_id,record_id), UNIQUE(tenant_id,stream_id,stream_sequence));

CREATE TABLE ingest_receipt (
  receipt_id uuid PRIMARY KEY, ledger_id uuid, tenant_id uuid,
  logical_shard_id text, chain_epoch bigint, commit_sequence bigint,
  previous_receipt_digest bytea, receipt_digest bytea, canonical_event_id uuid,
  UNIQUE(ledger_id,tenant_id,logical_shard_id,chain_epoch,commit_sequence));

Outbox and projection checkpoints reuse the same logical-shard/epoch/commit key.
Appendix O defines every required column, digest and atomicity constraint.
  • Create 32 hash partitions initially; measure partition size and lock contention before changing. Each partition receives indexes on (stream_id, stream_sequence), (record_type, recorded_at), (recorded_at), and BRIN(valid_start_s) when history is large.
  • Keep canonical_bytes and record_digest in PostgreSQL for authoritative replay. Large artifacts remain in object storage and are referenced by immutable manifests.
  • Enable and force row-level security for tenant tables, but treat it as defense in depth; the application policy decision and service identity are still mandatory.
  • Database roles used by services do not own tables and do not have BYPASSRLS. Migration and break-glass roles are separate, time-bound and fully audited.

#34.3 Atomic append algorithm

Table
One-record append with fencing, idempotency and outbox
append(ctx, receivedBytes):
  parsed, canonicalBytes, recordDigest = validate_and_canonicalize(receivedBytes)
  requestDigest = H(domain="REQUEST", ctx.operationFamily, canonicalBytes)

  retry SERIALIZABLE transaction on SQLSTATE 40001 with bounded jitter:
    INSERT idempotency_binding(scoped key, requestDigest, status='STARTED')
      ON CONFLICT DO NOTHING
    binding = SELECT idempotency_binding FOR UPDATE by scoped key
    if binding.request_digest != requestDigest: fail EQUIVOCATION
    if binding.status != 'STARTED' or binding.receipt_id is not null:
      return original receipt or in-progress status

    head = SELECT stream_head FOR UPDATE by tenantId, streamId
    require ctx.writerEpoch == head.writer_epoch
    require ctx.expectedStreamSequence == head.last_sequence
    nextSeq = head.last_sequence + 1
    shard = stable_shard(ctx.tenantId, ctx.streamId)
    nextPosition = allocate_shard_position(shard)  # gaps allowed on rollback

    authorize exact recordDigest and current context; fail closed on error
    INSERT record_ledger, subject/relation indexes, ingest_receipt, outbox_event
    UPDATE idempotency_binding SET status='COMMITTED', receipt_id=receiptId
    UPDATE stream_head SET last_sequence=nextSeq, last_record_id=recordId,
           last_receipt_digest=receiptDigest WHERE writer_epoch=ctx.writerEpoch
    COMMIT

  publisher reads committed outbox rows, emits at least once, and marks published.
  Consumer deduplicates by eventId and advances checkpoint with its state atomically.

PostgreSQL sequences can produce gaps on rollback; shardPosition therefore orders committed rows but is not required to be gap-free. streamSequence is allocated by the locked stream_head row and is gap-free for accepted records. A writer-epoch mismatch is terminal for that writer, even if it believes its lease remains valid.

#34.4 Batch append and multi-stream work

OperationAtomicity boundaryFailure behavior
single-stream batchOne transaction; expected starting sequence plus ordered RecordCoresAll commit or none; first invalid record rejects batch
independent bulk importOne transaction per record or bounded microbatchPer-item receipt; no fabricated batch atomicity
multi-stream semantic transactionAllowed only when all heads live in one database transaction and lock order is deterministicSerialize/retry whole transaction; bounded stream count
cross-service/cross-store workflowDurable saga with step receiptsComplete, compensate or escalate; never claim distributed rollback
external provider effectAction transaction plus provider idempotency/reconciliationUNKNOWN_EFFECT until proven; never blind retry

#34.5 Integrity chain and checkpointing

Table
Hash-chain and Merkle checkpoint profile
receiptDigest[n] = SHA256(
  "RTRACER\0INGEST-RECEIPT\0v1\0" ||
  canonical(receipt_without_digest_and_signature)
)

receipt[n].previousReceiptDigest = receiptDigest[n-1] within one ledgerId + tenantId + logicalShardId + chainEpoch. ShardHead stores the only chain tail; commitSequence is gap-free and transactional.
Every 65,536 committed receipts, emit LedgerCheckpoint {
  shardId, firstCommitSequence, lastCommitSequence, merkleRoot, terminalReceiptDigest,
  recordCount, createdAt, signerKeyEpoch, backupSnapshotRefs[]
}

Daily IntegrityScrub recomputes sampled leaves, complete recent windows and
all checkpoint chains; mismatch quarantines the shard from new projection release.
Data classDefault treatmentDeletion semantics
portable factual RecordCoreRetain according to declared lifecycle/legal classIf erasure is required, destroy protected payload/key material and append ErasureReceipt; never pretend the fact was never processed
PII-bearing identifier/evidenceField or artifact encrypted with scoped data-encryption keyCryptographic erasure plus object deletion, replicas/backup expiry and verification receipt
derived public projectionRebuildable, short retentionDelete immediately on source/policy change and invalidate cache/search/feed
security/audit metadataMinimized, separately authorized, immutable for defined periodRetain only non-content fields needed for accountability; expire under policy
raw telemetry/mediaTiered storage with explicit purpose and expiryDelete object bytes and segment keys; retain non-identifying manifest tombstone if permitted
legal holdScoped to named records/artifacts, authority and review dateSuspends only affected disposal; not a blanket tenant freeze
Table
Append-only does not mean retain every secret forever
The immutable property applies to the audit of decisions and relationships. Privacy-sensitive bytes can be separately encrypted, minimized, redacted and destroyed under an authorized disposal record. A tombstone must not preserve the deleted value in an index, log message, cache key or error string.