fix(recovery): support batched SQLite blob writes

This commit is contained in:
2026-08-19 19:20:05 +02:00
parent 21122e058e
commit ad55d47645
5 changed files with 374 additions and 65 deletions
+15 -3
View File
@@ -573,15 +573,27 @@ candidates until those controls are implemented.
### Recovery ledger for object effects
Every managed blob creation or integrity repair starts a Core recovery
operation in an independent committed transaction before Files protects or
writes bytes. The operation records tenant/blob identifiers, an opaque object
On PostgreSQL, every managed blob creation or integrity repair starts a Core
recovery operation in an independent committed transaction before Files
protects or writes bytes. The operation records tenant/blob identifiers, an opaque object
locator or locator digest, semantic SHA-256/size evidence, the recovery mode,
and a distributed lease fence. It never records file contents, ZIP passwords,
connector credentials, or a newly uploaded filename. New object keys are opaque;
legacy filename-bearing keys remain readable but repair operations record only
their digest and recover through the blob ID.
SQLite is a supported local-development database but permits only one writer.
Files therefore uses an explicit reduced-durability mode there: recovery intent
and its lease are written in the caller transaction, while a process-local
fence prevents competing effects in the same runtime. Commit makes the intent
durable before independent verification. A handled rollback reconstructs a
durable recovery operation and verifies compensation or forward completion.
A hard process loss before commit can leave an object without a surviving
ledger row, so SQLite is not a production recovery profile; after such a loss,
run a complete Files integrity scan and reconcile every reported orphan before
resuming writes. PostgreSQL retains the independent pre-effect durability
guarantee.
The Files business transaction then creates or updates the blob, version, and
asset rows. Its actual SQLAlchemy commit or rollback settles every pending
operation: