Tenancy Posture §8.3: service class, and why there is no QoS axis

Question 12 asked whether to add a quality-of-service dimension. No - because
we could not enforce it. Community PostgreSQL has no resource governor, so a
declared priority would be an unenforced claim in a declaration, which is what
retiring tenantIsolation was about. An axis implies graduation and enforcement
and this has neither.

Co-residents are equal, and a consumer whose latency cannot survive an
unprioritised neighbour escalates to P2. Service class is still declared, as a
category not a level: it informs placement, acts as a trigger, and gives
"acceptable degradation" in the noisy-neighbour artifact something to be
acceptable relative to - what batch tolerates is an outage for latency-critical.

Class mixture must be visible, because an unenforceable risk nobody can see is
worse than one that is stated. rapp-postgres now reports it and the live
instance already flags latency-critical beside batch.

Gateway-level prioritisation in a connection proxy is recorded as the known
escalation short of P2 - real, and infrastructure we do not run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
tegwick 2026-08-17 17:41:12 +02:00
parent 101e659725
commit e25545d9d0

View file

@ -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 |
| **P1P4** | Provisioning declaration plus the platform's isolation probes | Mechanical |
| **P1P2 (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 |
| **P1P2 (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:<grouping>:<name>` embeds headcount bands (`small`, `medium`, `large`)