Isolation is a checklist, not a logo.
The vendor says multi-tenant and the demo shows two logos in a switcher. Underneath, a column on a shared table may be the only wall, and the support tool can open any account. Check every path that reads or writes, not the switcher.

Before you ship or buy a multi-tenant product, fill an isolation checklist and give every row an owner and a pass or fail. Cover the data partition, auth boundary, job queues, support impersonation, and what a backup restore can overwrite. A shared database with a tenant column in the pitch is not isolation.
Multi-tenant is a boundary, or it is a shared drawer
A vendor says the product is multi-tenant. The demo shows two logos in a switcher. Underneath, a column on a shared table is the only wall, background jobs query without that column, and a support tool can open any account because “we have to help.” The logo switcher is not the boundary. The boundary is every path that can read or write.
This note is the TWIMCO Multi-Tenant Isolation Checklist. Each row is pass, fail, or not shown, plus an owner. You use it before you ship a tenant model or before you accept one in a purchase. It does not score a market. It asks whether a failure in one tenant’s data, queue, impersonation session, or restore can reach another. There is no live checklist tool for these rows. Scoping the product itself can start from the live custom product build brief. The checklist is still a page you fill.
PatientIQ project work connected patient-reported outcomes with hospital data and included reporting tied to CMS requirements. That is a public reason to care which institution’s information a screen, a job, or a restore can see. It is not a public case-study page, and it is not a claim about how their tenant walls were built. Wellthie project work turned complex healthcare data into decision context for consumers and businesses—two audiences whose options should not leak into each other by accident. Same limit: project context, not a published architecture. The public case to read for role-bounded access is Sutton|Place: banking desk, issuer, and operations do not automatically see one another’s position, and access to one part of an opportunity is not access to every part.
If you are buying, ask the vendor to walk the rows on their tenant, not on a slide. If you are building, assign an owner who can point at the code or the control, not a committee.
Five rows that decide whether the wall exists
Score each row pass, fail, or not shown. “They said so” without a place you can point is not shown. Not shown is not a pass.
Data partition. What key separates tenants, and where is it enforced—query layer, row policy, or separate store? A column that most queries remember to include is a fail until you can say what happens when a query forgets. Search indexes and file buckets count. A shared bucket with guessable keys is a drawer, not a wall.
Auth boundary. Is the tenant decided by a signed claim the server checks, or by a value the client sends and the server trusts? Switching logos in the UI proves the client can ask. It does not prove the server refuses the other tenant’s id. Session fixation across tenants, and an admin token that is silently global, are fails until scoped.
Job queues. Can a worker for tenant A read or write tenant B because the payload omitted the key, or because the worker uses a privileged connection and “knows better”? Name the queue or the job class. A single worker fleet is fine if every job carries the tenant and the worker refuses a missing one. A fleet that assumes the payload is already safe is a fail.
Support impersonation. Who may act as a tenant user, for how long, what they must record, and whether the tenant can see that it happened. “Support has a backdoor” with no time bound and no record is a fail. Impersonation that cannot be distinguished from the user in the audit log is a fail even if the intent was kind.
Restore blast radius. If you restore tenant A’s backup, what else can change? A cluster restore that rewinds every tenant is not an isolation story, even if backups “exist.” Pass requires a stated blast radius: this restore touches only these stores for this tenant, or it does not, and the owner has accepted the wider radius in writing. Unstated radius is a fail.
Add rows when they are real for the buy: admin cross-tenant reports, shared caches, webhook fan-out, and model prompts that include another tenant’s text. Do not add them to look thorough and then leave them blank. A blank is not shown.
The checklist does not pass while any of the five core rows is fail or not shown, unless a named owner has dated an exception and written the compensating control. “We will fix it next quarter” without an owner is a fail you are polite about.
How the work moves
Walk the isolation rows before you ship
- Data partition
Where the tenant key is enforced, including search and files.
- Auth boundary
Server-checked claim, not a client-supplied id the server trusts.
- Job queues
Workers refuse a missing tenant instead of assuming the payload.
- Impersonation
Who may act as a user, for how long, and what is recorded.
- Restore radius
What a restore of one tenant is allowed to overwrite.
If restore can overwrite another tenant, you do not have isolation, only a backup with a blast radius.
How to run the review without a theater demo
Sit with two people: one who knows the product surface, one who knows how jobs and backups actually run. Where they disagree, the row stays not shown until someone points at a control.
For a purchase, ask for a non-production tenant pair. Create a record in A. From a session in B, try to fetch it by id. Enqueue a job that prints its tenant. Open the support tool and see whether impersonation leaves an actor that is not the end user. Ask, in words, what a restore of A does to B. You are not pen-testing the vendor’s company. You are refusing to buy a logo switcher. If they will not show a second tenant, mark the rows not shown and do not narrate that as confidence.
For a build, do the same tests against your own staging before the first external tenant. The owner of each row signs pass only with a pointer: a policy name, a test name, a runbook step. A pointer to a slide is not shown.
Write exceptions as rows, not as a paragraph under the table you wished you had. Each exception has an owner, an expiry, and the other tenants it puts at risk. When the expiry passes, the row returns to fail until it is rebuilt or the exception is renewed on purpose. Evergreen exceptions are how isolation becomes a story the security questionnaire repeats and the worker code ignores.
On healthcare-shaped work such as the PatientIQ and Wellthie projects, the cost of a leak is not abstract: outcomes, hospital context, and decision support are consequential. That is why the checklist is a buying and shipping gate, not a blog diagram. On Sutton|Place, separate blocks of a deal keep their own disclosure status. Borrow the habit, not a fictional control matrix from that partnership. Your rows have to be about your stores.
Re-run the five core rows when you add a new store, a new worker, or a new support tool. Isolation rots at the edges you did not have when the first tenant launched. The checklist is cheap to repeat and expensive to skip after the second integration.
Walls that exist only in the pitch
Composites, not client findings.
The column. Tenant id is on the table. Two reports join without it. Both are “internal,” so nobody treats the join as a breach. The other tenant’s counts are now in a deck.
The global admin. A staff token can read every tenant, and every debug script copies that token. Impersonation rules exist for the UI and not for the script.
The helpful queue. A poison job is retried on a worker that logs the full payload to a shared log store. Isolation in the database, exhibition in the log.
The restore hero. The only recovery that has been rehearsed is “restore the cluster.” Tenant B learns about tenant A’s incident by losing the afternoon’s writes.
The support favor. An engineer updates a row by id sent in chat. No impersonation record, because nobody logged into the product. The wall is in the app and not in the console.
When a row fails, do not average it against the rows that passed. One fail on restore blast radius is enough to keep the checklist from passing. The unreproducible asset is your filled TWIMCO Multi-Tenant Isolation Checklist: five core rows, pass or fail or not shown, an owner on each, and any dated exception. A vendor’s SOC report does not answer these rows for you. Your pointers do.
Keep the checklist with the buying memo or the launch note. It sits beside security review, not instead of it. A product can encrypt disks and still trust a client-supplied tenant id. Conversely, a careful auth boundary does not answer whether backups rewind the neighborhood. Web applications work is the right conversation when the fails are in the product you are building. Business process automation fits when the leak is a job or a handoff between systems that forgot the tenant on the message.
Do not publish another tenant’s data as the example in your own test notes. Use synthetic tenants. The checklist is about the wall, not about borrowing real records to prove the wall.
Decision guide
Logo switcher versus a tenant wall
| Consideration | Looks multi-tenant | Holds a boundary |
|---|---|---|
| Demo | Two logos in a switcher. | A second tenant cannot fetch the first by id. |
| Jobs | A shared worker that “knows” the data. | Every job carries a tenant and fails closed without it. |
| Support | A global token in a chat paste. | Impersonation is time-bounded and distinguishable in the log. |
| Recovery | Restore the whole cluster. | Stated blast radius for one tenant, owned in writing. |
Put this into practice
- Copy the five core rows onto one page: data partition, auth boundary, job queues, support impersonation, restore blast radius.
- Mark each pass, fail, or not shown. Attach a pointer or an explicit not-shown reason. Name an owner.
- For a purchase, ask to see two tenants and one restore question. For a build, run those checks in staging before an external tenant arrives.
- Date every exception. Do not let “next quarter” sit without a name.
- If the page is red on queues or restore, do not describe the product as multi-tenant in the launch note. Bring the failed rows into a web applications scoping conversation. Use Sutton|Place as the public picture of access that is allowed to differ by role—and keep PatientIQ and Wellthie as project context for why health-shaped data makes a sloppy wall unacceptable, not as stand-ins for a control you have not pointed at.
A switcher proves the client can ask. The checklist asks whether the server, the worker, and the backup must refuse.
We build alongside the people doing the work.
Bring us the problem you’re thinking about.