[Privacy] A wiki page in the bin is exported, and comes back live on import #990

Closed
opened 2026-10-01 17:04:40 +00:00 by claude-bot · 2 comments
Collaborator

Found while fixing #830 (the export's prep, arcs and shelf).

What happens. export_campaign (routers/campaigns.py) selects wiki pages with no deleted_at filter, and import_campaign (services/import_service.py) never sets deleted_at. So a page a GM put in the bin travels in the file and comes back as an ordinary live page, with whatever audience it had.

Probed on the test world: the binned page "A torn page" answers 404 to a player at the source. After export and import it is a live table page the players of the new campaign can read.

Why it matters. Deleting a page is how a GM takes something away from the table. An export followed by an import (moving servers, restoring a copy, the same-server import in Admin) silently undoes that for every binned page. It is an audience widening, the same shape as the leaks the wiki crawl tests exist to stop.

Fix (to decide between, both small).

  1. Leave binned pages out of the export. Simple and safe; the bin's 30-day grace does not survive a move.
  2. Export them marked as deleted (with deleted_at), and import them into the bin, GM-only until restored. Keeps the grace period; needs the import to honour the marking and never to read a missing or malformed marking as "live".

Recommendation: (2) if the bin's contents are meant to survive a move, otherwise (1). Whichever is chosen, an older file that already contains binned pages cannot be told apart from live ones, so nothing can be done for files already exported.

Also check the same pattern for the other soft-deleted things the export walks: sessions in the bin, deleted discussion threads and posts, deleted handouts, deleted scenes and arcs (#830's new code already leaves those out), deleted quest objectives. Add a crawl-style test: for every soft-deletable table, a binned row is either absent from the file or comes back binned.

Refs #830, #734.

Found while fixing #830 (the export's prep, arcs and shelf). **What happens.** `export_campaign` (`routers/campaigns.py`) selects wiki pages with no `deleted_at` filter, and `import_campaign` (`services/import_service.py`) never sets `deleted_at`. So a page a GM put in the bin travels in the file and comes back as an ordinary live page, with whatever audience it had. **Probed** on the test world: the binned page "A torn page" answers 404 to a player at the source. After export and import it is a live `table` page the players of the new campaign can read. **Why it matters.** Deleting a page is how a GM takes something away from the table. An export followed by an import (moving servers, restoring a copy, the same-server import in Admin) silently undoes that for every binned page. It is an audience widening, the same shape as the leaks the wiki crawl tests exist to stop. **Fix (to decide between, both small).** 1. Leave binned pages out of the export. Simple and safe; the bin's 30-day grace does not survive a move. 2. Export them marked as deleted (with `deleted_at`), and import them into the bin, GM-only until restored. Keeps the grace period; needs the import to honour the marking and never to read a missing or malformed marking as "live". Recommendation: (2) if the bin's contents are meant to survive a move, otherwise (1). Whichever is chosen, an older file that already contains binned pages cannot be told apart from live ones, so nothing can be done for files already exported. **Also check** the same pattern for the other soft-deleted things the export walks: sessions in the bin, deleted discussion threads and posts, deleted handouts, deleted scenes and arcs (#830's new code already leaves those out), deleted quest objectives. Add a crawl-style test: for every soft-deletable table, a binned row is either absent from the file or comes back binned. Refs #830, #734.
Author
Collaborator

Picking this up (1 Oct), on fix/990-binned-not-exported, stacked on #830's branch since both change the export.

Taking the safe option for now: what is in the bin does not travel. A binned row is left out of the file along with everything that hangs off it, and the importer skips any row a file marks as deleted. The audit covers every table the export walks (pages, sessions, threads and posts, handouts, objectives and the rest), plus the zip's Markdown files, with a crawl-style test and a guard that fails when a new soft-deletable table is exported without being classified.

Whether the bin's contents should instead travel into the new campaign's bin is question X1 on the Questions page; it can follow if wanted.

Picking this up (1 Oct), on `fix/990-binned-not-exported`, stacked on #830's branch since both change the export. Taking the safe option for now: **what is in the bin does not travel.** A binned row is left out of the file along with everything that hangs off it, and the importer skips any row a file marks as deleted. The audit covers every table the export walks (pages, sessions, threads and posts, handouts, objectives and the rest), plus the zip's Markdown files, with a crawl-style test and a guard that fails when a new soft-deletable table is exported without being classified. Whether the bin's contents should instead travel into the new campaign's bin is question X1 on the Questions page; it can follow if wanted.
Author
Collaborator

Done in #998, merged 1 Oct (main 8192839d).

  • The export leaves out binned wiki pages and everything keyed on them (aliases, owners, appearances, relationships with either end binned, name targets, the zip's wiki/*.md and media/lore/), and a binned page's shelf card, pin and prep item, whose snapshot is a copy of the page.
  • The import skips any row a file marks deleted; a post marked hidden comes in hidden.
  • tests/export/test_export_bin.py proves each, and its guard enumerates every table with a soft-delete column and requires a ledger line saying what the export does with it.

Limits, stated in docs/API.md: a file exported before this fix may hold binned pages, and nothing can tell them from live ones; export again.

Still travels, deliberately: a cancelled session, a hidden post (as hidden), a reveal taken back, a Talk thread on a binned page (as about nothing, which is how the source shows it), and a card reveal of a binned page's card as the table saw it. That last one is #996 and question X3. Whether the bin should travel into the new campaign's bin is question X1.

Done in #998, merged 1 Oct (main 8192839d). - The export leaves out binned wiki pages and everything keyed on them (aliases, owners, appearances, relationships with either end binned, name targets, the zip's `wiki/*.md` and `media/lore/`), and a binned page's shelf card, pin and prep item, whose snapshot is a copy of the page. - The import skips any row a file marks deleted; a post marked hidden comes in hidden. - `tests/export/test_export_bin.py` proves each, and its guard enumerates every table with a soft-delete column and requires a ledger line saying what the export does with it. **Limits, stated in `docs/API.md`:** a file exported before this fix may hold binned pages, and nothing can tell them from live ones; export again. **Still travels, deliberately:** a cancelled session, a hidden post (as hidden), a reveal taken back, a Talk thread on a binned page (as about nothing, which is how the source shows it), and a card reveal of a binned page's card as the table saw it. That last one is #996 and question X3. Whether the bin should travel into the new campaign's bin is question X1.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
rbrooks/Quest-Board#990
No description provided.