diff --git a/canon/standards/tenancy-posture_v0.1.md b/canon/standards/tenancy-posture_v0.1.md index 5469291..8adf77e 100644 --- a/canon/standards/tenancy-posture_v0.1.md +++ b/canon/standards/tenancy-posture_v0.1.md @@ -457,6 +457,51 @@ in a YAML comment nobody re-reads is documentation, not control. selection is a commercial decision as much as a technical one; an operations-shaped repo should not hold it alone. +### 8.3 Service class — a placement input, never a priority + +A latency-critical consumer and a batch consumer can share an instance today +with nothing distinguishing them. `tenant-engine` sits on `flex-auth`'s +synchronous authorization path and chose a 5s statement timeout for that +reason; `audit-core`, co-resident, is not latency-critical. Nothing prioritises +between them. + +**The framework does not add a QoS axis, because the platform cannot enforce +one.** Community PostgreSQL has no resource governor: no per-role CPU or I/O +priority, no resource queues, no workload classes. Those exist in EDB's +enterprise variant, in Greenplum, and in SQL Server — not in what we run. A +declared priority level would therefore be an unenforced claim sitting in a +declaration, which is precisely what retiring `tenantIsolation` was about. An +axis implies graduation and enforcement; this has neither. + +**Decision 8.3.1 — co-residents are equal.** On shared substrate no consumer's +query yields to another's. A consumer whose latency requirement cannot survive +an unprioritised neighbour must escalate to `P2`. That is the honest mechanism +and it is the only one we have. + +**Decision 8.3.2 — service class is declared anyway**, as a category rather +than a level: `latency-critical`, `interactive`, or `batch`. It buys three +things, none of which is priority: + +- **A placement input.** Mixing `latency-critical` with `batch` on one instance + is a recognised mismatch. It may still be the right call — it is right today + — but it should be a decision, not an accident of who was provisioned when. +- **A trigger.** A `latency-critical` consumer acquiring a `batch` co-resident + is a recorded placement trigger under §8, on the same footing as noisy + neighbour. +- **An acceptance criterion for evidence.** The noisy-neighbour artifact in §13 + asks whether measured degradation is *acceptable*; without a declared class + that word has no referent. Degradation tolerable for `batch` may be an + outage for `latency-critical`. + +**Decision 8.3.3 — class mixture must be visible.** The platform reports which +classes are co-resident. An unenforceable risk that nobody can see is strictly +worse than one that is stated. + +The known escalation short of P2 is gateway-level prioritisation — ordering +submissions in a connection proxy by the requesting tenant's current +consumption. It is real, it is where the industry puts this when it must, and +it is new infrastructure we do not run. Recorded as the option, not adopted. + ## 9. Credentials as a tenancy control Short-lived leased credentials re-read at connection checkout, with @@ -558,7 +603,7 @@ E2 evidence.** | **E3** | `FORCE ROW LEVEL SECURITY` on every tenant table; no `BYPASSRLS` on leased roles; probe that a session without the GUC reads nothing; probe that a wrong GUC reads nothing; `EXPLAIN` comparison | Mechanical | | **E4** | Per-tenant credential demonstrated unable to connect to another tenant's substrate | Mechanical | | **P1–P4** | Provisioning declaration plus the platform's isolation probes | Mechanical | -| **P1–P2 (noisy neighbour)** | A recorded baseline of per-consumer resource usage; a run in which one consumer saturates its declared allowance; evidence that the governance controls **bind** (the greedy consumer is held at its limits) and that the degradation co-residents experience is **measured, recorded and judged acceptable**; the aggregate headroom at time of measurement | **Adversarial**, load-generated, with a review date | +| **P1–P2 (noisy neighbour)** | A recorded baseline of per-consumer resource usage; a run in which one consumer saturates its declared allowance; evidence that the governance controls **bind** (the greedy consumer is held at its limits) and that the degradation co-residents experience is **measured, recorded and judged acceptable against each one's declared service class** (§8.3); the aggregate headroom at time of measurement | **Adversarial**, load-generated, with a review date | | **R2** | Declared retention rendered; erasure horizon published and reported in the operator surface | Mechanical | | **R3** | Sweep evidence records: timestamp, dataset, identifiers removed, authorising policy reference | Mechanical | | **R4** | Erasure demonstrated across live data, backups and derived copies within the horizon | **Adversarial** | @@ -778,13 +823,10 @@ minimum-level vocabulary alongside isolation. *personal payload*, encrypted per subject and shreddable. Raised because a naive "R4 everywhere" target would instruct the audit service to destroy its own evidence. The answer is `audit-core`'s, not this framework's. -12. **Quality of service** — *owner needed.* The framework has no vocabulary - for saying one consumer's latency matters more than another's. - `tenant-engine` sits on `flex-auth`'s synchronous authorization path and - chose a 5s statement timeout for that reason; it shares an instance with - `audit-core`, which is not latency-critical. Nothing prioritises between - them. Either add a QoS dimension or state that all co-residents are equal - and latency-critical consumers must escalate to P2. +12. **Quality of service** — **resolved 2026-08-17.** Co-residents are equal; + a declared *service class* informs placement but never grants priority. + See §8.3. The question asked whether to add a QoS dimension; the answer is + no, and the reason is that we could not enforce one. **Routed elsewhere, deliberately.** The tenant identifier `tenant::` embeds headcount bands (`small`, `medium`, `large`)