Checklist: YSD-22058 (tenant closure) · drill kind tenant-closure ·
YSD-17106 Decision owner role: the service owner for svc-study-workspace
Machinery: libs/yemaya/study-workspace/src/continuity/disaster-recovery.ts
This had no document and no nearest guidance — nothing at all. It is also two
scenarios rather than one: tenant-data-export and tenant-closure share the
tenant-closure drill kind, because the export is the first half of the
closure and a drill of the closure necessarily performs it.
That sharing is the safety property. A closure that has not exported first is an unrecoverable deletion performed on somebody else's material.
Order, and why it is not negotiable#
- Export first, and verify the export before deleting anything.
- Then close.
⚠️ Nothing in a closure is reversible, and the tenant is by definition no longer around to tell you something is missing. A verified export is the only thing standing between a closure and a data-loss incident that surfaces months later.
What the export must contain#
The workspace's own answer to "what did this tenant have" is the same one the
backup uses: every study table, enumerated from the catalog rather than from a
list somebody maintains, filtered to the tenant. Plus the tenant's objects in
oshun-study, where the key grammar is tenant-scoped (YSD-3021), so the tenant
prefix is a real boundary and not a filter applied afterwards.
What the export must NOT quietly include: another tenant's material reachable through a shared work. If a source is shared, the tenant's annotations are theirs and the source is not. Exporting the source because it was reachable hands one tenant another's licensed material.
The steps#
| # | Action | Owner role | Expected |
|---|---|---|---|
| 1 | Produce the export, tenant-scoped at the key grammar and the table filter | service owner | — |
| 2 | Verify it — counts per table against the live tenant, and a spot read through the store rather than raw SQL | service owner | — |
| 3 | Deliver it, and get acknowledgement that it arrived and opens | service owner | — |
| 4 | Only then close: delete tenant rows and objects, leaving tombstones | service owner decides | — |
| 5 | Confirm shared sources survived, and that no other tenant lost access | service owner | — |
Step 5 is the one a closure gets wrong. A deletion that follows references rather than tenancy takes a shared work down with the tenant that referenced it.
Communication#
| Audience | Within |
|---|---|
| The tenant, with the export and what closure will remove | before step 4 |
| The rights owner, where licensed material was in scope | before step 4 |
Done means#
- The export was verified and acknowledged before anything was deleted.
- Tenant rows and objects are gone; tombstones remain.
- No other tenant's access changed.
- Recorded in the procedure exercise register.
The objective, and why there is not one#
This procedure states no duration objective, and that is a decision rather
than an omission. evaluateDrill refuses a drill record without one, so the
consequence is exact: tenant closure cannot be drilled today, and the reason
is not that nobody has written a number down.
Two things stand in the way, and neither is fixed by choosing a duration.
Step 3 waits on somebody outside. The tenant has to acknowledge that the export arrived and opens, and that acknowledgement is not ours to schedule. A whole-procedure objective would be a promise about how fast a departing customer answers their email, and the way to meet such an objective is to stop waiting for the acknowledgement — which is the one thing the order of operations above exists to prevent.
Steps 1 and 2 have no machinery to measure. There is no export-specific code
in the service; nothing has ever produced a tenant-scoped export, so there is no
floor under a number the way scripts/time-backup-restore.ts and
scripts/time-deletion.ts put one under theirs. A duration nobody has measured
is the fabricated measurement this programme keeps refusing.
What would change this, in order: build the export, measure steps 1, 2 and 5
against a real deployment, and state an objective over those three — leaving
steps 3 and 4 outside it exactly as yemaya-study-provider-change.md leaves its
rights decision outside its containment objective. The Expected column above
stays blank until then.
Known shortfall#
Nothing exercises this — zero mechanism runs, and no export-specific machinery was found in the service. The expected durations above are deliberately left blank rather than guessed, for the reasons in the section directly above. Read this as the order of operations that must hold, not as a rehearsed procedure.