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

@ -79,6 +79,38 @@ change that JSON and therefore the digest. A decision rendered against
approval A for request R cannot be replayed for request R' if the consumer
compares digests.
### What this digest is not — answering `INFD-IN-0001` R3
`informed-decision` asked whether its `view_hash` and this digest are the same
hash, since both are described as canonicalizing a binding. **They are not, and
they must not be merged.** Three hashes, three questions:
| Hash | Preimage | Answers |
| --- | --- | --- |
| `binding.digest` (here) | five fields: `action`, `actor`, `principal`, `purpose`, `target` | *which act* is approved |
| `binding.pdp_digest` | the PDP's own `NewDecisionBinding` digest, recorded at issue | *which decision request* this approval corresponds to |
| `view_hash` (`informed-decision`) | a canonicalized binding document additionally covering brief, packet, highlights, locale and UI release | *what a person was shown* when they bound themselves |
The overlap is only that all three canonicalize *something*. This engine's
digest deliberately covers five fields and no more: it exists so that
wrong-action, wrong-target and wrong-scope are distinguishable, and it has no
opinion about presentation, which does not exist for a machine-to-machine
approval. Widening it to cover a brief or a locale would change the digest of
an act whose act did not change.
This repository already keeps two digests apart for exactly this reason rather
than as a matter of taste — `binding.digest` and `pdp_digest` answer different
questions and are stored separately precisely so that a reader cannot infer one
property from the other. A third hash answering a third question is the same
pattern, not a duplication of it.
**The recommended relationship, which avoids two canonicalizations of one act:**
`view_hash`'s binding document should *carry this digest as a field* rather than
re-canonicalize `action`/`actor`/`principal`/`purpose`/`target` itself. Then
there is exactly one canonicalization of the act, computed here, referenced by
the presentation hash — and a mismatch is detectable rather than being two
independently correct answers about the same approval.
### Mapping from a flex-auth CheckRequest
| Claim binding | CheckRequest |