Say what the tenant check is, and what view_hash is not

gate-house (GH-DEC-2026-013) was right that our wording implied a fact
about the person. The tenant comparison is store isolation — does this
caller belong to the store this engine serves — and a registration-
supplied claim satisfies that while satisfying no doctrine about the
approver's own membership. Exact equality cannot see the difference, so
state it, and note that provenance gets recorded on the entry the way v4
records principal_type once the claim carries it.

Answer informed-decision's R3 in the claim contract: view_hash and
binding.digest answer different questions and must not be merged. Three
hashes, three questions. Recommend their binding document carry our
digest rather than re-canonicalize the same five fields, so the act has
one canonicalization and a mismatch is detectable.

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 1275879@bnt-lap001
Assistant-Session: eb464208-f821-41b2-bc5a-a6c33d92a8ad
This commit is contained in:
tegwick 2026-09-10 07:56:28 +02:00
parent 849c75bb09
commit 62233c7c52
3 changed files with 89 additions and 0 deletions

View file

@ -8,6 +8,30 @@ mode is explicit, file-backed, and refused with `--production`.
The verified `tenant` must exactly match the service's configured store tenant;
cross-tenant reads and mutations are rejected before object lookup.
**This check is store isolation, and it is not a statement about the person.**
It answers "does this caller belong to the store this engine serves", not "is
this human a member of the platform zone". `GH-DEC-2026-013` rules that a
key-cape human tenant claim may be supplied by the client registration rather
than asserted by the directory, and forbids a consumer treating the two as
equivalent for a decision turning on a fact about the person. Exact string
equality cannot see that difference — a string that matches exactly matches
whoever asserted it — so the difference is stated here instead.
Consequences this engine accepts deliberately:
- A registration-supplied tenant **is** admissible for admission to this store.
Admission means "arrived through a channel the platform registered", the
approver client is static and deployment-owned, and dynamic client
registration is excluded from key-cape by design.
- A registration-supplied tenant is **not** admissible for any doctrine that
turns on the approver's own membership — "an approver must be a member of the
platform zone" is a fact about the person, and this claim cannot carry it.
No such doctrine exists today; if `gate-house` issues one, it needs a
directory-sourced claim and this check does not become that claim by matching.
- When key-cape emits provenance alongside the tenant, this engine records it on
the approver entry the way schema v4 records `principal_type` — an evidence
reader should not have to infer provenance from a string that cannot carry it.
| Route | Required scope |
|---|---|
| create approval | `approval:create` |