Workspace backup¶
Purpose¶
Portable ZIP of the authoritative workspace (notebooks + corpus + config) so operators can move machines, remount Docker volumes, or recover after mistakes — then verify with corpus/notebook doctors. Archives are local files; Transcribe does not upload them.
Format¶
Envelope:
format: transcribe.workspace-backup,schema_version: 1Container: ZIP with
ZIP_DEFLATEDManifest member (required, zip root):
transcribe.workspace-backup.json
Package layout (role roots)¶
Absolute host paths are not authority. Members use fixed role prefixes remapped to current RuntimePaths on restore:
transcribe.workspace-backup.json
projects/ # TRANSCRIBE_PROJECTS_DIR tree
data/
config/ # settings, profiles, prompts, detection, interface menus
corpus/ # index, import/ocr/analysis runs, quarantine
ocr_preference_ledger.json # when present at backup time
inbox/ # only when includes.inbox
exports/ # only when includes.exports
Manifest fields (v1)¶
Field |
Required |
Meaning |
|---|---|---|
|
yes |
|
|
yes |
|
|
yes |
ISO-8601 UTC timestamp |
|
yes |
Application version string that wrote the archive |
|
yes |
Object: |
|
yes |
Object: |
|
yes |
Hex SHA-256 of the sorted file-index lines used at pack time |
|
no |
Operator notes; may list role names; must not be required for restore |
File index (internal, used to compute file_index_sha256): one line per packed file (excluding the manifest itself), sorted lexicographically by member path:
<path>\t<size>\t<sha256>
Verify recomputes this index over non-manifest members and compares the digest. Pack and verify stream file bytes (chunked) so large corpora do not require loading each member fully into memory.
Always include (when present on disk)¶
Entire projects tree for managed notebooks (
project.json,sources/,pages/,results/, and presentanalysis/,detection/,page_metrics/)data/config/**data/corpus/**data/ocr_preference_ledger.jsonwhen present
includes.projects, includes.config, and includes.corpus are always true in valid v1 archives. includes.ledger is true only when the ledger file was packed.
Optional includes (default off)¶
Flag |
Packs |
|---|---|
|
|
|
|
Always exclude¶
data/cache/**(includingarchive.sqlite) — disposable; rebuild after restore*.lockfiles*.partialfiles (interrupted zip writes).staging/directoriesProject-local
.cache/**and thumbnail cachesThe destination ZIP path itself when it would fall under a packed root
Create semantics¶
Refuse if the workspace corpus lock is held.
Refuse if any managed notebook holds an OCR or analysis job lock.
Refuse if the destination
.zipalready exists unlessforce/--force.Refuse when free disk space on the destination filesystem is below a fixed headroom (256 MiB) plus the estimated uncompressed payload size.
Write via
*.zip.partialthen atomic rename to the destination.Member names must stay under the role prefixes above (zip-slip rejected on write and read).
Default destination: {TRANSCRIBE_EXPORT_DIR}/backups/transcribe-workspace-<YYYYMMDD-HHMMSS>.zip.
Verify semantics¶
Open ZIP; require and parse the root manifest via
require_format(..., "transcribe.workspace-backup").Reject members that escape role roots (
.., absolute paths, unexpected top-level names).Require
projects/anddata/config/anddata/corpus/presence consistent withincludes(empty trees may soft-note).Recompute
file_index_sha256over packed files; mismatch → fail.
Verify does not mutate the workspace.
Restore semantics (v1)¶
Replace-only. Restore remaps archive role roots onto the current RuntimePaths (env/Docker mounts). Absolute paths recorded in notes are ignored for placement.
verifythe archive (fail closed).Refuse corpus lock or any notebook OCR/analysis job lock.
Refuse if the archive path resolves under a tree that restore will replace (
projects,data/config,data/corpus, andinbox/exportswhen those includes are true). Archives under{export_dir}/backups/are allowed even whenincludes.exportsis true (that directory is preserved during exports replace).Unless disabled, create a safety backup of the current workspace (same create path; default options — inbox/exports off) under
{export_dir}/backups/pre-restore-<stamp>.zip.Refuse when free disk space is below fixed headroom plus estimated restore payload (and safety backup size when enabled).
Replace role roots present in the archive:
Clear children of
projects_dir, then extractprojects/Replace
data_dir/config/anddata_dir/corpus/Replace ledger file when packed; leave local ledger as-is when the archive omits the ledger member
When
includes.inbox/includes.exports: replace those roots the same way (exports/backups/preserved when replacing exports)
Delete
data_dir/cache/when present (Archive/FTS rebuilds on next use).Run corpus doctor (
deep=true); report findings. Successful restore leaves doctor green or warnings-only for documented quarantine retention (corpus-integrity.md).
If replace fails after a safety backup was written, errors include the safety archive path so operators can recover.
Dry-run: perform verify + lock checks + archive-location guard + describe replacements (counts and mapped paths); write nothing.
Non-goals (v1)¶
Merge / per-notebook restore
Incremental or differential backups
Encryption or cloud upload
Treating
archive.sqliteas backup authorityIn-browser Streamlit transfer of full archives