# Plane P — Placement: prior knowledge and best practices > Research artefact — 2026-08-17. Supports `canon/architecture/adr-008-multi-tenancy-model.md` > (draft-2), plane P of four. Surveys external practice for which substrate > holds a tenant's data, and holds our `P0–P4` ladder against it. > **Contains strong external validation of draft-2's reframe, and one > expressiveness failure in the P ladder itself.** > Companions: plane I (identity), plane A (authorization), plane E (enforcement). ## 1. What the plane covers Which physical substrate holds a tenant's data, who decides, and what moving costs. Our ladder: | Level | Shape | |---|---| | P0 | Shares a database with another consumer | | P1 | Database per consumer, shared cluster | | P2 | Dedicated cluster per consumer | | P3 | Dedicated cluster per tenant | | P4 | P3 plus separate region or jurisdiction | ## 2. Validation: "isolation is a spectrum, not a discrete property" The operator's instruction to reframe draft-1 from a fixed model into a graduated framework is not merely defensible — it is Microsoft's stated position, in almost the same words: > "Instead of viewing isolation as a discrete property, consider it a spectrum. > You can deploy components of your architecture that are more isolated or less > isolated than other components in the same architecture, depending on your > requirements." > — [Azure Architecture Center — Tenancy models for a multitenant solution](https://learn.microsoft.com/en-us/azure/architecture/guide/multitenant/considerations/tenancy-models) The same page decomposes isolation across tiers exactly as our planes do — "you can use different levels of isolation for each tier", with a shared UI tier, a shared middle tier, and isolated databases given as the worked example. **Against our model:** draft-2's core move is externally corroborated by the most rigorous public taxonomy available. Worth citing in ADR §15, because it converts "we decided to do it this way" into "this matches the reference guidance", which matters for reviewers who will ask whether we invented a private vocabulary. ## 3. Validation: our E↔P coupling claim is independently confirmed ADR §3.2 asserts that the planes couple at the top — `E4` is only reachable at `P3` or above — and §4.4 asserts that `P0 → P1 → P2` does not raise the E level. Microsoft states the mechanism plainly: > "A key difference between tenants and deployments is how isolation is > enforced. When multiple tenants share a single deployment (a set of > infrastructure), you typically rely on your application code and a tenant > identifier that's in a database to keep each tenant's data separate. When > tenants have their own dedicated deployments, they have their own > infrastructure, so it might be less important for your code to account for a > multitenant environment." (ibid.) That is our E/P relationship derived independently: shared deployment ⇒ enforcement is application code (our E1–E3); dedicated deployment ⇒ enforcement is structural (our E4). ## 4. Finding: our P ladder cannot express per-tenant placement, and our own commercial section requires it This is the significant gap. Azure names two partitioning axes that our single ladder collapses: - **Vertically partitioned deployments** — "a combination of single-tenant and multitenant deployments. For example, you might have most of your customers' data and application tiers on multitenant infrastructures, but you deploy single-tenant infrastructures for customers who require higher performance or data isolation." Explicitly monetisable: "You can even charge customers a higher rate to use a single-tenant deployment." (ibid.) - **Horizontally partitioned deployments** — shared application tier, dedicated databases per tenant, targeted at the component that carries the load: "if you identify that specific components cause most of the load on your system, then you can deploy separate components for each tenant." (ibid.) Our P ladder assigns **one level per service**. `tenant-engine` is `P1`. `audit-core` is `P1`. There is no way to say *"P1 for most tenants, P3 for the three enterprise tenants who bought isolation"* — which is precisely the vertically partitioned model, and precisely what ADR §11's minimum-level plan tiers imply. The contradiction is internal to draft-2: §11.1 says "a tier may require `E3 P2`", but if only some tenants hold that tier, the delivering service occupies two P levels at once. The posture vector as specified cannot represent that state, so a service in it would have to either overclaim (declare P2 for everyone) or underclaim (declare P1 and misrepresent what the tier delivers). Both are §6 violations. **Proposed amendment.** Either: 1. **Make P a per-tenant-class level rather than a per-service one** — the vector carries a default plus exceptions: ```yaml tenancy: current: { I: 2, A: 3, E: 2, P: 1 } placement_exceptions: - tenants: ["tenant:enterprise:*"] P: 3 reason: "isolation tier" ``` 2. Or **declare per-tenant placement out of scope** for the framework and say so, accepting that plan tiers selling isolation are then unmodellable. Option 1 is more work and is the honest one, because the estate has already anticipated tiered isolation. Azure also flags the cost: "your codebase needs to be designed to support both multitenant and single-tenant deployments", and migration between them must be planned for (ibid.) — which is exactly what our §7 portability rules already provide, so we are better positioned for this than most. ## 5. Cell-based architecture: the pattern our ladder skips ADR §18.8 asks whether to evaluate cells. The literature gives enough to sharpen the question. - A cell is "a complete, independent instance of the service" with **a fixed maximum size** — compute, storage, supporting services and configuration for a defined blast radius ([Rackspace — cell-based architecture on AWS](https://www.rackspace.com/blog/cell-based-architecture-aws), [AWS guidance for cell-based architecture](https://github.com/aws-solutions-library-samples/guidance-for-cell-based-architecture-on-aws)). - Cells are logical partitions on a **partition key** — customer ID ranges or tenant ID — and "the data required for or generated by each cell is also partitioned, so that there is no replication of data between cells" (ibid.). - The sizing argument is the point: "by capping the size of each cell… you can potentially predict and address failures more easily. This leads to a higher MTBF" (ibid.). And "it is important to identify the proper partition key to minimize cross-cell interactions" (ibid.). - Cells are the bulkhead pattern applied to tenancy — AWS files it under fault isolation, REL10-BP04 ([AWS Well-Architected — use bulkhead architectures to limit scope of impact](https://docs.aws.amazon.com/en_us/wellarchitected/2022-03-31/framework/rel_fault_isolation_use_bulkhead.html)). - Azure's equivalent is the **Deployment Stamps pattern**: "each stamp serves a predefined number of tenants, allowing you to scale almost linearly and serve increasing numbers of tenants" ([Azure — Deployment Stamps pattern](https://learn.microsoft.com/en-us/azure/architecture/patterns/deployment-stamp)). Azure also calls deployments "supertenants or stamps" and describes the tenant→deployment mapping table as a first-class component. **Against our model:** a cell is not a rung on our P ladder — it is a different axis. P measures *how much is shared*; a cell measures *how large a shared unit is allowed to get before you make another one*. Our `platform-pg` is, in cell terms, an uncapped cell: §16 of the ADR computes a ceiling of roughly six consumers but nothing enforces it, and there is no second cell to overflow into. That reframes §18.8 usefully. The question is not "should we adopt cells" but "**what is `platform-pg`'s declared maximum size, and what happens at the boundary?**" — a question we can answer now, cheaply, and which the connection ceiling already forces. Azure also names **bin packing** as the assignment strategy and stresses maintaining "a record of your customers and the infrastructure where their data and applications reside so that you can route their traffic to the correct location" — a tenant→deployment mapping table. We have no such record; the placement facts in ADR §1 were assembled by inspection. ## 6. Placement is a commercial decision, and the guidance says so first Our §11 treats commercial expression as a constraint to be managed. Azure puts it the other way round: > "Selecting a tenancy model isn't only a technical decision. It's also a > commercial decision." — considering business objectives, compliance, scale, > automation capacity, and SLAs (ibid.). And on the economics, matching our §14 rejection of R3/P3-everywhere: "if a single tenant requires a specific infrastructure cost, 100 tenants probably require 100 times that cost", with ongoing maintenance time-consuming at scale (ibid.). Conversely single-tenant is appropriate "if you expect that your business will have only a few customers… even though it's more costly". **Against our model:** ADR §8.2 proposes placement ownership to `railiance-platform`, an operations-shaped repo. This guidance suggests placement policy is *jointly* commercial and technical — which strengthens the case that `adaptive-pricing` must be a co-signer on §18.2, not only on §18.5. ## 7. Our tenant taxonomy is a recognised hard case Azure's B2C guidance describes our exact situation: > "If your customers are consumers, it's often more complicated to relate > customers, tenants, and users… consider whether your solution might be used > by families, groups of friends, clubs, associations, or other groups that > might need to access and manage their data together. For example, a music > streaming service might support both individual users and families, and it > might treat each of these account types differently when it separates them > into tenants." (ibid.) Our ADR-0013 taxonomy contains `consumer`, `family`, `community`, and `association` verbatim. It also notes that if tenants are individuals, "you might need to consider how you handle personal data and about the data sovereignty laws in each jurisdiction" — which is our `P4` and, combined with plane A §6, the tenant-deletion gap. ## 8. Testing placement is a named obligation > "Whichever isolation model you choose, be sure to test your solution to verify > that one tenant's data isn't accidentally leaked to another **and that any > noisy neighbor outcomes are acceptable**." (ibid.) Two evidence artifacts, not one. ADR §13 covers the leak half (P1–P4: "provisioning declaration plus the platform's own isolation probes") and says nothing about noisy-neighbour behaviour. Azure suggests deliberate fault injection (Chaos Studio) to verify resilience. **Proposed amendment to §13:** add a noisy-neighbour evidence artifact for P1 and P2 — a demonstration that one consumer saturating its connection or CPU allowance does not breach another's. `rapp-postgres` already sets database-scoped `connection_limit`, `statement_timeout` and `idle_in_transaction_session_timeout` precisely for this, and ADR-0001 §3 argues resource exhaustion is an isolation failure — but nothing proves the limits hold under load. ## 9. Summary against our ladder | Finding | Verdict | |---|---| | "Isolation is a spectrum, not a discrete property"; different tiers at different levels | **Validates draft-2.** Cite in §15. | | Shared deployment ⇒ app-code enforcement; dedicated ⇒ structural | **Confirms E↔P coupling** independently. | | Vertical partitioning: some tenants pooled, some dedicated, explicitly monetised | **Gap.** P is per-service; cannot express per-tenant placement that §11 requires. | | Horizontal partitioning: shared app tier, per-tenant DB for the hot component | **Unmodelled.** Our P assumes whole-service granularity. | | A cell has a **fixed maximum size**; stamps scale near-linearly | **Reframes §18.8.** Ask "what is `platform-pg`'s declared max size?", not "should we adopt cells". | | Tenant→deployment mapping table is a first-class component | **Missing.** Our placement facts were assembled by inspection. | | Tenancy model is a commercial decision as much as technical | **Amend §8.2.** `adaptive-pricing` should co-sign placement ownership. | | B2C/family/association tenancy is a recognised hard case | Our taxonomy hits it verbatim; jurisdiction concerns feed P4. | | Test for leakage **and** for acceptable noisy-neighbour outcomes | **Amend §13.** No noisy-neighbour evidence artifact exists. | ## Sources - [Azure Architecture Center — Tenancy models for a multitenant solution](https://learn.microsoft.com/en-us/azure/architecture/guide/multitenant/considerations/tenancy-models) - [Azure Architecture Center — Architectural approaches for a multitenant solution](https://learn.microsoft.com/en-us/azure/architecture/guide/multitenant/approaches/overview) - [Azure Architecture Center — Deployment Stamps pattern](https://learn.microsoft.com/en-us/azure/architecture/patterns/deployment-stamp) - [Azure Architecture Center — Considerations for updating a multitenant solution](https://learn.microsoft.com/en-us/azure/architecture/guide/multitenant/considerations/updates) - [AWS Well-Architected — REL10-BP04 Use bulkhead architectures to limit scope of impact](https://docs.aws.amazon.com/en_us/wellarchitected/2022-03-31/framework/rel_fault_isolation_use_bulkhead.html) - [AWS Well-Architected — How do you use fault isolation to protect your workload?](https://wa.aws.amazon.com/wellarchitected/2020-07-02T19-33-23/wat.question.REL_10.en.html) - [AWS Solutions Library — Guidance for cell-based architecture on AWS](https://github.com/aws-solutions-library-samples/guidance-for-cell-based-architecture-on-aws) - [Rackspace — Cell-based architecture on AWS](https://www.rackspace.com/blog/cell-based-architecture-aws) - [Ryan Harrison — Cell-based architecture engineering guidelines](https://guidelines.ryanharrison.co.uk/architecture/cell-architecture/) - [Anudeep Balla — The guide to cell-based architecture](https://medium.com/@anudeepballa7/the-guide-to-cell-based-architecture-58cf607f9754) - [AWS Well-Architected SaaS Lens (PDF)](https://docs.aws.amazon.com/pdfs/wellarchitected/latest/saas-lens/wellarchitected-saas-lens.pdf) - [hidekazu-konishi — AWS SaaS multi-tenant architecture guide: tenant isolation, pool and silo models](https://hidekazu-konishi.com/entry/aws_saas_multi_tenant_architecture_guide.html)