diff --git a/docs/tenant-claim-contract.md b/docs/tenant-claim-contract.md index 27c9705..965952b 100644 --- a/docs/tenant-claim-contract.md +++ b/docs/tenant-claim-contract.md @@ -116,10 +116,32 @@ carries tenants, the same code stops supplying the zone and starts enforcing agreement with it — no second migration, and no window in which a stale registration silently wins. -It is safe only because client registrations are static and deployment-owned. -KeyCape excludes dynamic client registration by design; a self-service client -able to name its users' tenant would be a straightforward escalation, and this -rule must be revisited if that exclusion is ever lifted. +### Condition of the capability + +This is not a caveat on the reasoning; it is a condition of the capability, and +it is stated here so a future change to registration policy has to confront it. + +> **A client-declared tenant is safe only while client registrations are static +> and deployment-owned.** If KeyCape ever admits dynamic client registration, +> anyone able to register a client can name its users' tenant and relabel +> unplaced users into a zone. The deliberate binding becomes an escalation. That +> change may not be made without first deciding what happens to client-declared +> tenants — and removing this paragraph is not that decision. + +Recorded at the request of informed-decision, who will hold the approver +registration and asked for it in the contract rather than in a message. + +A document can be missed, so the condition is also enforced. +`TestRegistrationBoundTenantRequiresStaticRegistration` +(`src/internal/server/oidc/tenant_precondition_test.go`, KEY-WP-0030) asserts +both halves together: that a client-declared tenant still issues, and that +discovery advertises no registration endpoint. Whichever is removed first, the +failure points at the other — which is the part that matters, since +`tests/profile` has long asserted the endpoint's absence on its own and that +assertion reads as discovery metadata rather than as a warning about relabelling +users. Dynamic client registration is a deliberate exclusion in +[SCOPE](../SCOPE.md); this ties the tenant capability to that exclusion so the +two cannot drift apart silently. Covered by `src/internal/server/oidc/human_tenant_test.go`, including the relabel refusal.