Files
james.maesandClaude Opus 5.5 18ae80740b perf(chain): normalized detail coverage table and sweep floors
The chain writer re-read the whole late-detail lookback every 30 s and
probed the GIN array index once per detail (18.4 s, 1.78M buffer hits per
tick in production), and the coverage trigger's EXISTS overlap check ran as
a cached generic plan that sequentially scanned worm_audit_chain for every
inserted link.

- worm-audit:13: worm_audit_chain_detail (detail_id PK, chain_id), one
  append-only row per covered detail, written by the chain trigger in the
  same statement as the link and backfilled under the chain advisory lock.
  WORM guards and grants like the other tables; no foreign keys.
- The trigger inserts coverage rows and lets the primary key reject a
  detail covered twice. The purge deletes coverage before its links.
- lateDetails probes the coverage primary key; both sweeps read only ids
  above per-JVM sweep floors, with a full sweep after restart and hourly.
- Verification aggregates the chain's own detail lists once and breaks if
  the coverage table disagrees. Link hash inputs are unchanged.
- Memory and H2 backends: the writer records coverage rows itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 07:40:33 -05:00

1.3 KiB

Upgrading qbit-worm-audit

Detail coverage table (0.1.0-RC.4)

Apply changeset worm-audit:13 from the rendered DDL (or your copy of it) before or with the new jar. It takes the chain advisory lock, creates worm_audit_chain_detail with its append-only guards and grants, backfills it from the existing chain, and replaces worm_audit_reject(), worm_audit_detail_coverage() and worm_audit_purge(). The jar requires the table: its chain writer reads it every tick. The GIN index worm_audit_chain_detail_coverage is no longer used but is kept so an RC.3 writer still running during a rolling deploy keeps an indexed probe; a later changeset drops it. Memory and H2 hosts need no migration beyond creating the new table (the writer fills it).

Table help bundle (unreleased)

Nothing to do. The qbit applies help/qbit-worm-audit.yaml at the end of produce(), filling only help slots the host has not set. No schema or seed changes: the settings row is still seeded by the database script (changeset worm-audit:10) and nothing else is seeded.

WormAuditSettings.seed(config) is now @Deprecated for PostgreSQL hosts (the script seeds row 1). It still works and remains the way for memory and H2 hosts to create row 1. The settings reader falls back to the configured values while the row is absent.