Re-review fixes R2, R3, R4, R5 and R6 (job side):
- R3: Apply refuses a plan with nothing to rewrite (409 nothing-to-do, no
job, no backup). Only the first apply keeps a pre-workflow-storage
backup; later applies (after a Cancel, a rerun) take a pooled safety
backup, forced on whatever the policy, so one copy is never pruned.
- R4: a second-connection writer test runs against the live job loop; with
its pause removed the writer hits "database is locked" (4 of 5 links).
- R5: the digest tool loads only database/workflow_documents.py by path (no
package start-up, no log handler) and opens a stopped database with
immutable=1, so it leaves no -wal/-shm; a live one is read through its WAL.
- R6: a backup that fails on a damaged document says which one in the job
line.
- R2: README's changelog says images recorded by this version use the new
form from the first start, and the way back is the earliest
pre-workflow-storage backup (or a pre-update backup if the job never ran).
Final review fixes I1, I2 and I3 for the workflow storage dedupe:
- I1: the migration always takes a verified backup, whatever
maintenance.safety_backup says; the plan reports backup.policy
"required" and the disk check counts it.
- I2: that backup is prompts.db.pre-workflow-storage_<stamp>, outside the
pruned prompts.db.backup_* pool and kept until the user removes it; the
job's last line and the preview name it, and the legacy restore accepts
it. README's changelog warns that an older version opens and restores a
rewritten database but shows no workflows, and says how to go back.
- I3: tools/workflow_text_digests.py writes the sha256 of every record's
stored texts (read-only; inline before the rewrite, through the accessor
after), so a diff before and after proves byte identity.
- A row the migration could not rewrite is listed in the job's errors and
named in its last line, and Reclaim space still runs.
The reviewed maintenance plan gains workflow_storage. Applying it starts
"Store each workflow once": kind maintenance, records admission,
cancellable, groups changed/protected/errors.
- The promised verified safety backup comes first; a failed backup ends the
job with nothing rewritten. The apply's up-front disk check covers it.
- Old-form rows are rewritten batch by batch on the event loop's executor,
with progress after each committed batch. Cancel stops between batches;
a failed batch rolls back whole and fails the job with a coded message.
Either way every record reads as before and the next apply continues.
- When every row was looked at, "Reclaim space" starts: exclusive (runs
alone), not cancellable. It checks the disk for VACUUM's copies of the
live pages, then sweeps, runs VACUUM and truncates the WAL. If another job
holds the registry it does not start, and the finished migration says so
and names Optimize database.
- No image or video file is opened; tests track every open under the
output folder and compare the media bytes and mtimes.