Decisions, risks and open questions¶
Part of the temporary reversible deletion plan. The decisions feed the deletion ADR (slice S0).
1. Decisions¶
Decided by Chris (5 October 2026)¶
| # | Decision | Effect on the plan |
|---|---|---|
| D1 | A 30-day restore window, configurable, fixed per item when it is deleted. It is the user-facing window, for searches and projects | Restore window §2 |
| D2 | No actual permanent deletion. Nothing is ever physically erased: no purge job, no "Delete permanently now", no study, search, project or stored-file deletion. After the 30 days an item leaves the users' Recently deleted view and users can no longer restore it; the data stays in the database, detached and marked, indefinitely. T-POL-01 stays "not approved" for everything |
Purge and file clean-up dropped (former slices S8a, S8b, S12); restore window; integrated plan rules ACD-R18, ACD-AE17 and AC-R2a-57 kept intact |
| D3 | Permissions. Search delete and restore (within the window): RemoveSearch holders. Project delete: the owner only. Project restore (within the window): the owner and application administrators. After the window: application administrators only. No one can erase |
Behaviour |
| D6 | A Bulk PDF upload in progress is cancelled, then the deletion proceeds (the 12 August draft's approach) | In-flight work §2 |
| D12 | Running search imports and bulk study updates are cancelled, then the deletion proceeds (replaces the earlier "wait" recommendation). New cancel paths are needed for both | In-flight work §3 and §4; slices S3c and S3d |
| Q7 | Keep the existing import clean-up. A failed or cancelled search import still deletes the Studies it wrote before it was ever shown. Reason: that is clean-up of a failed upload, not user data, so it does not conflict with "no actual permanent deletion" | In-flight work §3.1; the no-erasure architecture test allow-lists it |
| Q8 | The proposed performance bound is the initial target: a 100,000-Study search moves in under 10 minutes, with save p95 within 20% of idle during the sweep | DL-R1S-13 |
Decided by Chris (14 October 2026)¶
| # | Decision | Effect on the plan |
|---|---|---|
| Q3 | Project restore: the owner within the restore window, plus application administrators, identified by the existing application-administrator capability. The authority programme does not need to name a new one | The S2a recovery policy and the S8 administrator routes use the existing check; ADR-024 §8 |
| D13 | The explicit FEAT-024 administrator maintenance and backfill routes refuse a deleted project. Its kept statistics stay frozen exactly as they were until it is restored | Implemented as slice S2c, reusing the S2a refusal shape; ADR-024 §7 |
| S3d-A | A version 1 bulk update stuck in Parsing (option A): the deletion waits at most 30 minutes since the job last changed, then treats it as abandoned and proceeds |
Implemented in S3d (BulkStudyUpdateDeletionParticipant.Version1StaleAfter): the participant logs a warning and appends one BulkStudyUpdateAbandonedForDeletion ledger record naming the job; nothing is erased; ADR-024 §6 |
Recommendations that stand (Chris informed; no objection)¶
| # | Decision | Recommendation |
|---|---|---|
| D4 | Does a restored search keep its screening and annotation? | Yes, exactly. Reservations are not revived; derived screening fields are recalculated against the current settings; answers to questions deleted meanwhile are removed |
| D5 | Members' access while a project is deleted | Hidden from all members; memberships kept and returned unchanged on restore; the owner sees it in Recently deleted during the window |
| D7 | The production cut-over | Move production from the bulk-update baseline to main only after the MVP is accepted on staging, with deletionLifecycle on in the same promotion (rollout §5) |
| D8 | The data model | "Detach and mark" for searches; a project-level state for projects (data model) |
| D9 | The uncommitted August work in .worktrees/bulk-pdf-deletion-lifecycle |
Preserve it as-is (for example committed to a local archive branch, never pushed unless Chris asks), cite it in ADR-024 as superseded, do not merge its code. This plan does not touch that worktree |
| D10 | Stored files | Kept. Under D2 nothing deletes them; the user guide must say so |
| D11 | Is a reason required? | Optional in the MVP, shown in Recently deleted; required when the canonical impact preview arrives (R2c) |
New recommendations (not yet decided)¶
| # | Question | Recommendation | Alternatives |
|---|---|---|---|
| R-A | Work in the project that does not belong to the item being deleted (another search's import, a bulk update that touches none of the deleted search's Studies) | Wait for it, without refusing; cancel only the item's own work. Cancelling unrelated work would discard a colleague's upload or edit for no gain (in-flight work §5) | Cancel all running imports and bulk updates in the project for any deletion |
| R-B | How do application administrators restore after the window? | Two administrator API routes in the MVP, no admin screen. It is meaningfully smaller (no web slice, no M3 design, no user-guide page); after-window restores should be rare; a screen can read the same routes later (restore window §3) | A minimal restricted "Deleted items" screen now |
| R-C | Should application administrators also restore projects within the window through the UI? | No: the administrator routes cover it; the UI list is for owners | An "All projects" filter for administrators on Recently deleted projects |
| R-D | Version 1 bulk updates cannot be rolled back, so a deletion must wait while one applies | Enable bulkStudyUpdateAtomicApply (version 2) in production before or with the cut-over, under ADR-020's own approval, so every bulk update can be cancelled (rollout §5) |
Keep version 1 and accept waits of up to 30 minutes since the job last changed (Version1StaleAfter), after which the job is treated as abandoned and a ledger record is written (decision S3d-A) |
| R-E | Cancelling a version 1 bulk update during a search deletion | Wait instead: its scope is unknown until it applies, so a cancel might discard changes to other searches | Cancel version 1 updates before they apply for search deletions too |
Explicit non-goal¶
Permanent erasure of any deleted data, by policy, schedule or request, is out of scope. It needs its
own decision (T-POL-01), a legal and retention review and its own ADR
(restore window §6).
2. Risks¶
| # | Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|---|
| K1 | A read that ignores ProjectId still shows a moved Study (an id load without a project check, a global scan) |
Medium | Medium: a deleted Study visible or editable through one path | S1's id-load audit and architecture test; the leak catalogue test; the write guard refuses edits regardless |
| K2 | Fold interplay: pending entries stranded under a holding id, or returned into the overlay | Medium | High: a wrong served count | The pending-free move rule; the zero-pending check; FEAT-024 owner review; soak drills |
| K3 | Restore after the project's settings changed leaves stored derived fields drifted, so rebuilds refuse | High without the fix | Medium: families stay on live fallback | Re-persist and deleted-question clean-up inside the restore's fence; drift check in acceptance |
| K4 | Serving a deleted project's kept statistics on restore misses a change made while it was deleted | Low | High: a wrong served count | The write paths keep rows exact or stale them (statistics §6); scheduled maintenance made to skip deleted projects; restore-without-rebuild parity in tests and the projectDeleteRestore drill; fallback option: stale every family on restore |
| K5 | Cancelling an upload races the agent's claim, or clean-up of a cancelled upload depends on the search link | Medium | Medium: a stuck deletion or orphaned storage | The cancel's own race handling (ClaimedForProcessing joins the wait); S3b tests for clean-up after unlink and after project deletion; Bulk PDF owner review |
| K5a | A cancelled import keeps writing after its clean-up (a batch saved after the cancel), leaving unrevealed Studies | Medium without the checks | Medium: orphaned Studies | The parse's start and per-batch status checks; the runner replays the idempotent clean-up after the parse has ended and checks that no unrevealed Study is left before detaching |
| K5b | A cancelled job re-raises its fence after the deletion's release | Medium without guards (#4062 makes re-admission real) | High: the project stays fenced with no owner; imports and bulk updates refused | Fence ordering; #4062's admission guards (a prerequisite of S3c and S3d); the parse's own status check; late-admission tests |
| K5c | A version 2 rollback ends RollbackQuarantined |
Low | Medium: the deletion is blocked until an engineer resolves it | ADR-020's existing procedure; the deletion shows BulkStudyUpdateQuarantined and alerts |
| K5d | A version 1 update applying when a deletion arrives cannot be cancelled | Medium while version 1 is in use | Low: the deletion waits at most 30 minutes since the job last changed, then treats it as abandoned (logged and in the ledger) | R-D; decision S3d-A |
| K5e | Cancelling someone else's running work surprises them | Medium | Low to medium: an import or bulk update has to be redone | Only the item's own work is cancelled (R-A); the dialog lists what will be cancelled; the job's owner sees the reason |
| K6 | A waited job never ends (a stuck import, upload processing with no hard time limit) | Low | Medium: a deletion pending for a long time; the item stays usable meanwhile | BlockedReason and the alert after WaitAlertHours; runbook |
| K7 | An image rollback while items are deleted | Low | Medium: deleted projects reappear, and the baseline's deletion erases again | Restore-all before rolling back; ExtraElements keeps the fields; runbook |
| K8 | Large sweeps slow saves or hold the statistics fence too long | Medium for very large searches | Medium | Batching; the 100,000-Study benchmark against the initial target; typed-busy refusals for other operations |
| K9 | Deletion racing an import, bulk update or recalculation | Medium | High without the waits | The wait set; one sweep per project; new-work refusals; the fence admitted only after the waits |
| K10 | Divergence from the integrated plan | Low | Medium: rework when canonical collections arrive | The X-DEL mapping in the README; D2 keeps the plan's no-erasure rules; the deletion state is a top-level field ready for conversion |
| K11 | Storage cost of keeping everything for ever | Certain | Grows with use: each 1% of the 10.7 GB Study collection that ends up deleted keeps about 107 MB plus index entries; the share is unknown until the Bramble rehearsal (#4068) gives search and project sizes | Gauges of detached Studies and deleted projects; monthly review against Atlas storage; a future erasure policy remains possible because deleted data is scoped by holding id and operation |
| K12 | Users assume deleted data is erased | Medium | Medium (privacy expectation) | Dialog copy and user guide say plainly that SyRF keeps deleted data |
| K13 | On staging, turning the deletion flag off forces Bulk PDF upload off (startup rule) | Certain when used | Low (staging) | Documented in rollback; prefer a fix-forward |
| K14 | A production release from main before the MVP removes deletion |
Depends on D7 | High (user-visible regression) | D7 |
| K15 | The uncommitted August work is lost, or merged by mistake | Low | Medium | D9 |
| K16 | Shared searches (linked to several projects) behave unexpectedly | Low | Medium | Explicit tests; only this project's link and Studies move |
3. Open questions¶
| # | Question | Who answers | Needed by |
|---|---|---|---|
| Q1 | How large are the largest searches and projects in production? Answered later from the production-copy rehearsal on Bramble (#4068), not by querying production. It also sizes the storage risk (K11) | The #4068 rehearsal | S4a benchmark; K11 estimate |
| Q2 | Are any production searches linked to more than one project? Also from the #4068 rehearsal | The #4068 rehearsal | S4a tests |
| Decided 14 October: the existing application-administrator capability (see above) | — | ||
| Q4 | Should running data exports be waited for (planned, with a 1-hour staleness bound) or allowed to finish with mixed content? | Chris | S3b. S3b-2 (#4212) implements the planned wait with the 1-hour bound; Chris to confirm |
| Q5 | Who owns and reviews the statistics-owned IsProjectDeleted writer and the maintenance skip? |
FEAT-024 owner | S2, S6 |
| Q6 | Is a 2-day staging restore window during acceptance acceptable, returning to 30 days afterwards? | Chris | S9 |
| Decided: keep it (see D-table) | — | ||
| Decided: the proposed bound is the initial target | — |