Principal is the requesting party, not the approver
informed-decision asked whether its binding.principal and ours name the same field, since both GH rulings said its slice canonicalizes "two of the five". They do not: ours is the party on whose behalf the act is performed, taken from the decision request's subject, while theirs is the approver — which appears here only as an entry and never in binding. Only target overlaps. Records the four-role distinction normatively in docs/approval-claim.md and guards it with a test asserting the act digest is insensitive to the approver while the approver stays recorded on the entry. Folding approver identity into the digest would now break view_hash's assumption here rather than silently in that repository. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QDzGbdDFnVJBxDgdp7RvpH Assistant: claude-code Assistant-Model: opus Assistant-Process: 2191554@bnt-lap001 Assistant-Session: d69bb7c3-b7b2-41c4-8287-6baef48c0993
This commit is contained in:
parent
2fdb01d42a
commit
a0a602976e
3 changed files with 81 additions and 1 deletions
|
|
@ -2,7 +2,7 @@ import json
|
|||
from pathlib import Path
|
||||
|
||||
from approval_engine.binding import binding_digest
|
||||
from tests.conftest import approve, binding
|
||||
from tests.conftest import approve, binding, validity
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
|
@ -89,3 +89,29 @@ def test_presentation_changes_cannot_change_the_approved_act(engine):
|
|||
}.items():
|
||||
other = approve(engine, extra_binding={**act, **presentation, field: replacement})
|
||||
assert engine.claim(other.id)["binding"]["digest"] != original_claim["binding"]["digest"]
|
||||
|
||||
|
||||
def test_approver_identity_is_not_in_the_act_digest(engine):
|
||||
"""`binding.principal` is the party on whose behalf, never the approver.
|
||||
|
||||
Answers `informed-decision`'s `principal_role_overlap` question. The
|
||||
approver is recorded as an entry, so two approvals of the same act bound by
|
||||
different people share one digest — which is why a presentation hash that
|
||||
must commit to *who was shown this* cannot get that from our digest.
|
||||
"""
|
||||
act = binding()
|
||||
first = engine.create(act, validity(), required_count=1)
|
||||
first = engine.add_entry(first.id, "user:approver-a")
|
||||
second = engine.create(act, validity(), required_count=1)
|
||||
second = engine.add_entry(second.id, "user:approver-b")
|
||||
|
||||
expected = binding_digest(act)
|
||||
assert engine.claim(first.id)["binding"]["digest"] == expected
|
||||
assert engine.claim(second.id)["binding"]["digest"] == expected
|
||||
|
||||
# The approver is still distinguishable — recorded, not hashed into the act.
|
||||
assert [e["subject_id"] for e in first.entries] == ["user:approver-a"]
|
||||
assert [e["subject_id"] for e in second.entries] == ["user:approver-b"]
|
||||
|
||||
# And changing who the act is *for* does change the digest.
|
||||
assert binding_digest(binding(principal="someone-else")) != expected
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue