Delivery reachability audit and bounded repair
Use this runbook when plan-driven delivery reports a missing, incomplete, or indeterminate serving state, or when an upgrade leaves a physical-pool root in question. The durable root in the platform SQLite database and the immutable catalog object are the authorities. Do not infer a root from an object-store listing, a filename, or a dashboard response.
The sequence is:
capture evidence → make a consistent backup → stop writers → audit →
repair dry-run → review evidence → bounded quarantine apply → verify/rollback
Keep the instance non-serving while the audit or repair is in progress. A failed check is a stop condition; it is not permission to retry with a new identity.
Capture evidence and make a rollback boundary
Before stopping the process, save the readiness response, image digest, configuration revision (without secret values), deployment/target IDs, and logs. The authenticated operator snapshot is useful for incident correlation:
GET /api/v1/projects/{project}/delivery/operator
It reports the target revision, active generation, admitted pools, roots, reader/writer leases, GC cycles, delete intents, and degraded reasons. The offline audit remains authoritative for catalog reachability.
Create a complete instance backup outside LEAPVIEW_HOME and record its
checksum before any repair:
leapview admin backup --out /srv/backups/leapview-before-delivery-repair.tar
sha256sum /srv/backups/leapview-before-delivery-repair.tar \
> /srv/backups/leapview-before-delivery-repair.tar.sha256
The full archive covers the control plane and configured in-home DuckLake,
artifact, runtime, and local managed-data boundaries. --database-only is
only a control-plane checkpoint; it is not a recoverable analytical point
unless the corresponding catalog and data backup is independently consistent:
leapview admin backup \
--out /srv/backups/leapview-control-before-delivery-repair.db \
--database-only
Stop the LeapView process and all delivery/build/refresh workers using the deployment's maintenance mechanism. Preserve the current volume, logs, and backup until the incident is closed.
Run the read-only reachability audit
The audit enumerates the active durable root set for one admitted physical pool, then verifies each exact catalog object and its read-only DuckLake closure. It acquires no destructive offline lock, does not migrate SQLite, and has no object-store deletion path:
leapview admin delivery audit --pool-id POOL_ID
The output is stable text evidence that can be attached to the incident:
mode: audit
pool_id: POOL_ID
root_revision: 42
root_count: 1
root: published/GENERATION_ID
status: active
catalog_digest: sha256:...
object_key: catalogs/sha256/....ducklake
created_at: 2026-08-18T12:00:00Z
candidate_id:
generation_id: GENERATION_ID
lease_id:
expires_at:
data_files: 12
delete_files: 0
verification: passed
For every root, the audit binds the root to its admitted compatibility tuple, reads the immutable catalog bytes, checks the catalog and object metadata digests, opens DuckLake read-only, requires one retained snapshot and zero live inlining, and verifies every referenced data/delete object is present in the same immutable pool. It fails closed on a missing or changed SQLite root, missing/corrupt objects, incompatible admission evidence, an ambiguous root, or an unknown closure. A failed audit emits no successful result; preserve the backup and follow the applicable recovery branch below.
For an S3 physical pool, DuckLake also requires the target-scoped credential bootstrap used for the target's analytical runtime. The offline adapter never falls back to ambient process credentials; if that bootstrap is unavailable, the audit and repair fail closed and the target's normal credential/bootstrap configuration must be restored before retrying.
Prepare an exact repair dry-run
Only repair a root printed by a successful audit. Copy every identity exactly;
do not derive an object key from a digest or substitute a newer timestamp.
--created-at and --expires-at must be RFC3339 UTC timestamps with Z (the
CLI rejects a non-UTC offset). The required and optional fields are:
| Flag | Source | Requirement |
|---|---|---|
--pool-id |
pool_id |
Required; exact admitted physical-pool identity. |
--kind |
root prefix |
Required; build, candidate, published, rollback, lease, retained, or quarantined. |
--source-id |
root suffix |
Required; exact durable source identity. |
--catalog-digest |
catalog_digest |
Required; immutable sha256: digest. |
--object-key |
object_key |
Required; exact immutable catalog key. |
--created-at |
created_at |
Required; RFC3339 UTC. |
--candidate-id |
candidate_id |
Include when printed. |
--generation-id |
generation_id |
Include when printed. |
--lease-id |
lease_id |
Include when printed. |
--status |
status |
Usually active; default is active. |
--expires-at |
expires_at |
Include when non-empty; RFC3339 UTC. |
Run without --apply first. This repeats the exact SQLite-root, artifact,
digest, and closure checks but does not acquire the destructive lock or mutate
rows:
leapview admin delivery repair \
--pool-id POOL_ID \
--kind published \
--source-id GENERATION_ID \
--generation-id GENERATION_ID \
--catalog-digest 'sha256:...' \
--object-key 'catalogs/sha256/....ducklake' \
--status active \
--created-at '2026-08-18T12:00:00Z'
The command has one fixed action: quarantine. There is no --action, raw
object key, catalog rewrite, or delete flag. A dry-run error means the root
changed, is absent, or its physical closure is not provable; do not apply a
command that did not pass this check.
Apply the bounded quarantine
After reviewing the audit output, backup checksum, root identity, and dry-run
logs, repeat the exact command with --apply:
leapview admin delivery repair \
--pool-id POOL_ID \
--kind published \
--source-id GENERATION_ID \
--generation-id GENERATION_ID \
--catalog-digest 'sha256:...' \
--object-key 'catalogs/sha256/....ducklake' \
--status active \
--created-at '2026-08-18T12:00:00Z' \
--apply
Apply re-verifies before opening the writable control-plane connection and
records the bounded quarantine action as offline-admin. For a build root,
the seal is failed; for a candidate, its lifecycle is failed; for a
retained, lease, or existing quarantined root, the registry row is
retired. A published or rollback root is never silently removed from the
active serving pointer. Quarantine leaves the catalog object, Parquet files,
and DuckLake metadata untouched and creates an auditable protection root.
There is deliberately no physical deletion in this command. Do not follow a
repair with leapview admin storage cleanup --apply as a substitute for
reachability repair. GC may only act later through its own fenced mark,
revalidate, and conditional-delete protocol after the root is no longer
protected.
Recovery branches and fail-closed rules
Incomplete seals or missing serving identity
An unverified/preparing seal, candidate without a serving-state identity, or
legacy generation with an empty identity is not a serving root. Do not edit
SQLite status or identity columns. If the audit can prove the exact build
root and closure, quarantine it with the bounded command; otherwise rebuild
and reseal with the current target revision, or restore the last validated
backup.
Missing root or object
An object that exists without the exact durable SQLite root is not repairable: the repair command rejects root drift even when bytes happen to match. A missing catalog object, digest mismatch, missing referenced file, or unknown DuckLake closure also fails the audit and repair dry-run. Preserve both the backup and the physical namespace, then reconcile from the original durable publication or restore. Never fabricate a root row or move/copy Parquet files.
Incompatible application or catalog upgrade
If persistent state remains backward compatible, roll back to the prior immutable application artifact and verify readiness. If a migration changed SQLite or DuckLake incompatibly, do not start the old binary against the new state. Restore the complete validated instance backup instead, preserving the failed state and upgrade logs. Follow Upgrades and migrations for the application rollback boundary.
SQLite-control loss
When SQLite is unavailable or corrupt, the audit and repair commands cannot establish an authoritative root and must not be run against a guessed object. Keep traffic stopped. Restore into the configured instance boundary with an explicit checkpoint of the current state:
leapview admin restore \
--from /srv/backups/leapview-before-delivery-repair.tar \
--current-out /srv/backups/leapview-control-loss-current.tar \
--confirm
Use --database-only only when the analytical catalog, Parquet/object store,
and control backup are known to be the same recovery point. After restore,
rerun the audit, verify readiness and a representative governed query, then
use the normal rollback command for a retained generation when appropriate:
leapview rollback GENERATION_ID
Do not create a replacement publication to probe an indeterminate outcome; reconcile the original durable publication or restore again.
Verification after repair or rollback
- Keep the maintenance boundary until
leapview admin delivery audit --pool-id POOL_IDpasses. - Confirm the expected active generation, target revision, pool admission, and serving-state identity.
- Check that the quarantine event and actor appear in the audit/event stream.
- Run one representative governed semantic query and dashboard check.
- Preserve the audit output, dry-run/apply output, backup checksum, and logs with the incident record.
If any identity, digest, closure, admission, or recovery-point check is ambiguous, leave readiness failed and stop. The safe outcome is retained state plus evidence, not deletion or a guessed repair.