coulomb-social/docs/release/client-data-export-review-2026-10-30.md
tegwick 16c685f956
Some checks failed
Use-case regression gate / usecase-regressions (push) Has been cancelled
Prepare attended source-date supervisor and recovered-pair rehearsal
Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a18e2d-f513-7742-b8e7-12af0b744ff3
2026-10-30 22:58:56 +01:00

5.6 KiB

Client data export and schema inventory

The operator export covers a selected tenant's application records and locally retained content. It addresses the data-export part of the business-app service contract; instance teardown, backup expiry and productive offboarding acceptance remain separate. This source has not been deployed and does not change the sealed storage release proposal.

export_client_dataset produces a private ZIP with a JSON manifest and original content files. It includes members, their local session principals, spaces, membership grants, assigned group/permission definitions and attributable admin history. It includes archived spaces, assets, page aliases and immutable revisions, including revisions of deleted pages. It never follows a body link, fetches remote resources or exports another tenant's files or record values.

Passwords, credential-bearing sessions and transient OIDC state are excluded. The schema inventory lists their storage separately. App-local principals must have unusable passwords; an unexpected usable credential refuses export rather than copying or silently discarding it. Independent backups and process logs stay under operator retention. Exporting data does not delete any of these stores or revoke sessions.

The operational inventory also names the prepared supervisor's private date-operations journals outside CONTENT_ROOT. They can retain original private index bytes, plan and backup metadata. The app cannot read that root store; operator offboarding must account for any retained client bytes and their explicit expiry separately. The supervisor rehearsal creates no production journal.

The inventory derives field names, database columns, types, nullability and relations from the loaded Django models. Every application field has an explicit classification. A new model or unclassified field refuses export until reviewed. The inventory also describes session/admin/configuration tables and the generated authorization join tables. Page bodies, metadata, filenames, attachments, revisions and admin text can contain arbitrary personal data; structured field categories are not a claim that free text has been inspected or anonymized.

Operator use

Run against an independently verified, externally quiesced database/content pair. Prefer the isolated retained restore for inspection. The source assertion below does not establish live admission, a writer fence or snapshot coherence. The SQL read uses a repeatable-read, read-only PostgreSQL transaction; file inventories and hashes before/after archiving detect ordinary content drift. Neither replaces external quiescence.

uv run manage.py export_client_dataset --inventory
uv run manage.py export_client_dataset \
  --tenant '<exact client tenant id>' \
  --quiesced-source \
  --output /private/operator/export/client.zip

The output directory must already exist with private permissions. The command requires an output outside the checkout and content root, refuses symlinks and overwrites, and publishes only after validating the archive's actual member hashes. The archive and staging file use mode 0600. Terminal output contains only counts, archive digest and incomplete-offboarding status; original record values and file paths remain inside the private archive. Hashing streams large files.

Cross-tenant relationships, duplicate storage slugs, unresolved content journals, unattributed content, links/special files and unattributable deleted-object admin history refuse. Resolve their ownership before repeating the export; the command does not repair or delete source data. An external-only content binding refuses. External references on spaces that also have local content remain listed in the manifest for owner reconciliation; their presence does not prove remote content has been captured. Do not call that export complete until those bindings are resolved for the client.

Verification and remaining acceptance

Synthetic tests cover tenant isolation, assigned permissions, local principal and membership records, aliases/assets/deleted-page revisions, session/password exclusion, ambiguous ownership and source refusal, content drift, private outputs, no overwrite and schema drift. The full make check gate includes the required browser journeys.

scripts/rehearse-client-export.py runs the exact source as an explicit overlay on the retained candidate, using the internal isolated recovery network and a read-only content mount. It checks every archive member hash against the selected tenant's source files, verifies all source SQL tables/files remain unchanged and removes the temporary private archive. It reports no original record values. The public proof is client-data-export-rehearsal-2026-10-30.json.

Native result: one User, Member, Space and SpaceMembership, plus all 81 selected local content/revision files, exported with matching archive hashes. There were no external bindings or attributable admin events in this recovered client. All 13 source SQL tables and 82 source files (including the excluded operational writer lock) remained unchanged. The temporary private archive was removed. make check passed all 340 tests with zero skips, including required browsers.

Before §6.2 acceptance, release the reviewed implementation and verify a coherent operator export for the current target; resolve remote/unattributed data; arrange private delivery to the client; define the separately authorized instance teardown, session revocation, process-log disposition and primary/mirror/protected-kit backup expiry. The existing independent-kit no-expiry protection must not be silently overridden. No client offboarding or productive deletion is authorized by this implementation or its tests.