Rule the tenant-provenance question: bounded gap, and the claim must say which

key-cape has no adapter populating the directory user tenant, so every
human token fell back to the default and approval-engine refused it by
exact match — presenting as a failed approval rather than as a
registration defect. It built a registration-bound resolution, then
declined to ratify its own design because the second option writes a
cross-tenant capability into the issuer. That reading was right and the
question is ours: what may be a source of a principal's identity is a
Core Rule, not a runbook.

Directory-sourced is the terminal state. A registration is a statement
about the actor; a tenant is a property of the principal; sourcing the
second from the first collapses two identities the estate keeps
distinct, in the direction that widens.

The registration-bound shape is admissible anyway, as a declared
bounded gap, and the reason is not that the design is careful. It is
that the case distinguishing it from the correct resolution fails
closed: where registration and directory disagree, issuance is refused
rather than resolved either way. And the same code turns from supplying
the zone into enforcing agreement with it the moment the directory
carries tenants, so it converges by subtraction.

That general property is section 3 and neither request asked for it.
A transitional shape is admissible where it fails closed on exactly the
case that distinguishes it from the correct resolution, and
inadmissible where it fails open there. It is section 8's asymmetry
applied to transitions, and it is what makes this grant and
GH-DEC-2026-011's decline one rule rather than two defensible calls: a
promise that fails open is a permission, a promise that fails closed is
a gap, and only the second is a thing a register can hold.

Two conditions strengthen what key-cape wrote about itself. Refusal on
disagreement is normative, including against a future change that
prefers the directory — picking any winner converts a refusal into a
silent cross-tenant assertion. And lifting the dynamic-registration
exclusion voids the rule rather than reopening it; key-cape wrote "must
be revisited", which implies the answer might survive review, and it
would not.

The finding they did not ask for is section 5. The tenant claim is a
bare string, so a consumer cannot tell a tenant the directory asserted
about the person from one a registration supplied about the client they
came through. approval-engine exact-matches that string and is relying
on the second while its contract reads as the first. That is
GH-DEC-2026-010 one layer down — a sound check whose reader infers a
property it does not carry. The claim must carry its provenance;
the mechanism is key-cape's.

Gap registered at net-kingdom@f9e1611.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012viPor8WJNCbV64ipwewrm

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 1754332@bnt-lap001
Assistant-Session: 9c8ac536-ff5e-46a3-8ab1-a548bde25fc0
This commit is contained in:
tegwick 2026-09-09 23:20:42 +02:00
parent 1fb9f29d49
commit 16c1d46d5d

View file

@ -1833,3 +1833,214 @@ Requested by `informed-decision` (`INFD-IN-0001`, hub intake `01a08610`) before
its architecture, with three candidate rulings, their costs, the self-dealing objection
argued against itself, and an explicit list of what it was *not* asking for. Unblocks
`INFD-WP-0001` T05 and T07, and `KEY-WP-0013-T02`.
## GH-DEC-2026-013 — A client registration may supply a human principal's tenant only as a declared bounded gap, and the claim must carry its provenance
```yaml
id: GH-DEC-2026-013
kind: decision
title: A client registration may supply a human principal's tenant only as a declared
bounded gap, and the claim must carry its provenance
status: resolved
owner: Bernd Worsch
repo: gate-house
standard: net-kingdom/canon/standards/security-layer-model_v0.8.md
source_note: key-cape/docs/tenant-claim-contract.md and src/internal/server/oidc/token.go
humanTenant (KEY-WP-0013-T05); relayed by informed-decision
requested_dispositions:
- approved
- revised
- rejected
affects:
- gate-house
- key-cape
- approval-engine
- access-engine
- user-engine
- informed-decision
- net-kingdom
- ops-warden
decided_by: Bernd Worsch
rationale: 'key-cape has no adapter populating the directory user tenant, so every
human token falls back to the default tenant and approval-engine refuses it by exact
match. Two resolutions were possible: source the tenant from the directory, or let
a client registration bind it. Directory-sourced is the terminal state, because
a tenant is a property of the principal and a registration is a statement about
the actor; sourcing a principal attribute from the actor collapses two identities
the estate keeps distinct, and supplying a tenant the directory has not assigned
widens rather than attenuates. The registration-bound shape is nonetheless admissible
as a declared bounded gap rather than refused, because its distinguishing case fails
closed: where the registration and the directory disagree, issuance is refused rather
than resolved in either direction. That is the general property this record states
— a transitional shape is admissible where it fails closed on exactly the case that
distinguishes it from the correct resolution, and inadmissible where it fails open
there, which is why GH-DEC-2026-011 declined ops-warden a transitional fail_open
and this record grants key-cape its transitional binding. Three conditions attach:
refusal on disagreement is normative rather than a design choice, the exclusion
of dynamic client registration is a normative precondition whose lifting voids the
rule rather than reopening it, and the gap is registered with an owner for the directory
adapter. One finding is added that was not asked for: the tenant claim is emitted
as a bare string, so a consumer cannot tell a tenant the directory asserted about
the person from one a registration supplied about the client, and a consumer relying
on it for the first is relying on the second. The claim MUST carry its provenance.'
created: '2026-09-09T21:18:11.679012Z'
updated: '2026-09-09T21:18:11.679012Z'
```
## Context
`key-cape` binds the approval chain to the landlord zone (`tenant:platform`), and
`approval-engine` compares the tenant claim by exact string equality. **No adapter
populates `domain.User.Tenant`**, so every human token fell back to `tenant:coulomb` and
an approver token would have been refused downstream — presenting as a *failed approval*
rather than as a *registration defect*, which is the failure mode that makes this worth
ruling on rather than leaving to implementation.
Two resolutions were available: source the tenant from the directory, or let a client
registration declare it. `key-cape` declined to choose unilaterally on the ground that
the second writes a cross-tenant capability into the issuer, which reads as doctrine
rather than implementation. That reading is correct and the question is Gate House's:
it is about what may be a source of a principal's identity, which is a Core Rule, not a
runbook.
It reached us relayed by `informed-decision`, which was asking about its own client
registration and passed on a question that was not its own. `key-cape` has already
built the registration-bound shape, and built it carefully — this record rules on a
design that exists rather than on a proposal.
## Decision
### 1. Directory-sourced is the terminal state
**A principal's tenant is sourced from the identity layer's record of the principal.**
A client registration is a statement about the **actor** — the client the person
authenticated through. A tenant is a property of the **principal**. Sourcing the second
from the first collapses two of the three identities the estate keeps distinct
(principal, actor, runtime identity), and it collapses them in the direction that
widens: a registration supplying a tenant the directory has not assigned gives the
principal an attribute the identity layer never asserted about them. **Delegation
attenuates and never widens.**
The condition being routed around is a missing adapter, not an absent owner. A missing
implementation in the identity layer is fixed in the identity layer.
### 2. The registration-bound shape is admissible as a declared, bounded gap
**Not refused, and not blessed as permanent.** `key-cape` may ship what it has built,
under §3's conditions and registered as a gap.
The reason it is admissible rather than forbidden is precise, and is not that the design
is careful. It is that **the case distinguishing it from the correct resolution fails
closed.** Where the registration declares a zone and the directory has placed the user
in a different one, `humanTenant` refuses to issue rather than picking a winner. Either
answer would be a silent cross-tenant assertion, and the design says so. A registration
can bind a zone for a user the directory has not placed; it can never relabel one it has.
`key-cape`'s further observation is what makes the gap bounded rather than open-ended:
the same code turns from *supplying* the zone into *enforcing agreement with* it the
moment the directory carries tenants — no second migration, and no window in which a
stale registration silently wins. A transitional shape that converges on the terminal
state by subtraction is a different object from one that will have to be unwound.
### 3. The general property, which is why this is granted and `GH-DEC-2026-011` was declined
**A transitional shape is admissible where it fails closed on exactly the case that
distinguishes it from the correct resolution, and inadmissible where it fails open
there.**
This is §8's asymmetry applied to transitions, and it is the rule that keeps these two
decisions consistent rather than merely both defensible:
- `ops-warden` asked for a dated transitional `unknown: fail_open` (`GH-DEC-2026-011`).
**Declined.** The distinguishing case — an unclassified subject reaching an unreachable
engine — is exactly where the transitional shape fails **open**. It is behaviourally
identical to the violation for the whole of its life, so the transition licenses the
thing the rule forbids and merely dates it.
- `key-cape` binds a tenant at registration. **Granted.** The distinguishing case —
registration and directory disagreeing — fails **closed**. The transitional shape and
the terminal state differ only where nobody is served either way.
A transition is a promise about the future. **A promise that fails open is a permission;
a promise that fails closed is a gap.** Only the second is a thing a register can hold.
### 4. Three conditions
1. **Refusal on disagreement is normative.** Row four of `key-cape`'s table is not a
design choice it may later optimise. A registration MUST NOT relabel a
directory-placed principal, and MUST NOT resolve the conflict in either direction.
Any future change that picks a winner — in either direction, including preferring the
directory — voids this permission, because it converts a refusal into a silent
cross-tenant assertion.
2. **The exclusion of dynamic client registration is a normative precondition, and
lifting it VOIDS this rule rather than reopening it.** `key-cape` writes that a
self-service client able to name its users' tenant would be a straightforward
escalation, and that the rule "must be revisited" if the exclusion is lifted. That is
too weak and we are strengthening it: revisiting implies the answer might survive
review. It does not. If dynamic client registration is ever admitted, the
registration-bound shape is void on that day and the directory becomes the only
source, whatever state the adapter is in. Stated that way so that lifting the
exclusion cannot be a small change made by someone who never reads this record.
3. **Registered as a declared gap under §13**, with an intended owner for the directory
adapter, so it cannot quietly become the permanent answer by nobody minding it. Per
§13, an intended owner is a proposal **to** a repository, not an assignment **onto**
it; this record does not name one.
### 5. The finding that was not asked for: the claim must carry its provenance
`key-cape` emits `tenant` as a bare string. A consumer cannot tell a tenant **the
directory asserted about the person** from a tenant **a registration supplied about the
client they came through**. `approval-engine` admits an approver by exact-matching that
string, and it is therefore relying on the second while its contract reads as though it
relies on the first.
**This is the shape of `GH-DEC-2026-010`, one layer down.** There, a PEP held a decision
and could establish which request it was for but not who issued it, while a mechanical
test read as though it discharged both. Here a consumer holds a tenant and can establish
that the string matches, but not whether the identity layer ever said it about this
person. In both cases the check is sound and the property a reader infers from it is not
present.
**The `tenant` claim MUST carry its provenance** — whether the value was asserted by the
directory about the principal, or supplied by the registration — and a consumer MUST NOT
treat the two as equivalent for any decision that turns on a fact about the *person*.
Exact-match admission on a registration-supplied tenant is admission on the client's
say-so.
The mechanism is `key-cape`'s: this record names the property, not the field. Note that
the same rule from `GH-DEC-2026-011` §3 applies to how it is recorded — two sources, one
claim value, and the record must distinguish them even though the string is identical.
It is `unknown` and `absent` again, in the identity layer.
**Sequencing:** this does not gate `KEY-WP-0013-T02`. The registration may be created
under §2 today. What must not happen is the path being described as validated while a
consumer cannot see which fact it is relying on.
## What this does not rule
Not ruled: whether `approval-engine`'s exact-match admission is the right gate, which is
`approval-engine`'s. Not ruled: which repository owns the directory adapter. Not ruled:
the choice of `tenant:platform` itself, which is settled by operator decision
`5ed3fb35-eca9-413a-82b9-95171ba85bf6` and is not doctrine.
## Reversal condition
§2 reverses on the day the directory populates the principal's tenant: the permission is
spent, not merely unused, and §1 governs alone.
§3's general property reverses if a case is found where a transitional shape failing
closed on its distinguishing case is nonetheless the more dangerous option — which would
mean the asymmetry rule has an exception, and §8 would be the thing under review rather
than this record.
§5 reverses if the two provenances are ever proven indistinguishable in effect, i.e. if
no consumer's decision turns on the difference. That is a claim about every present and
future consumer and we do not expect it to be made good.
## Provenance
Raised by `key-cape` (`KEY-WP-0013-T05`, `docs/tenant-claim-contract.md`), which built
the shape, documented its own escalation risk, and declined to ratify its own design.
Relayed by `informed-decision` while asking about its own registration — a repository
passing on a question that was not its to carry. `GH-DEC-2026-011`'s decline and this
record's grant are the two halves of §3, which neither request asked for and which is
the part of this record most likely to matter later.