test: enforce the presentation exclusion contract for approval digests

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a07ff8-19d0-7820-b4d0-1353833cb7fc
This commit is contained in:
tegwick 2026-09-10 18:39:30 +02:00
parent 62233c7c52
commit adb5cb0a9a
4 changed files with 109 additions and 1 deletions

View file

@ -79,6 +79,27 @@ 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.
### Presentation exclusion — GH-DEC-2026-015 §4
`binding.digest` MUST cover exactly the five act fields above and MUST NOT cover
presentation material: `view_hash`, brief, packet, highlights, locale, UI release
or a presentation wrapper. Those belong outside the act binding. Callers MUST
NOT smuggle presentation into `target` or another act field; target remains the
actual effect scope, including its nested scope fields. The engine does not
classify arbitrary target values as presentation or silently discard scope.
This is a compatibility constraint, not design intent. Widening the digest to
presentation would change approval identity on a UI release and could introduce
a mutual hash dependency. `tests/test_claim_contract.py::test_presentation_changes_cannot_change_the_approved_act`
asserts through durable issue/claim that changing presentation leaves the digest
and stored act unchanged, while changing any of the five act fields changes the
digest. A mutation that hashes the whole supplied binding must fail that test.
This supplies GH-DEC-2026-015's condition for `informed-decision` to carry the
engine's digest in `view_hash`; consumer adoption and its own verification remain
with that repository. GH-DEC-2026-016's declared human-control bind enforcement
is a separate requirement and is not implemented by this contract assertion.
### What this digest is not — answering `INFD-IN-0001` R3
`informed-decision` asked whether its `view_hash` and this digest are the same

View file

@ -0,0 +1,21 @@
{
"ruling": "GH-DEC-2026-015",
"condition": "normative and tested exclusion of presentation from native binding.digest",
"status": "condition-implemented-source",
"test": "tests/test_claim_contract.py::test_presentation_changes_cannot_change_the_approved_act",
"focused_tests": 7,
"full_suite_output": "........................................................................ [ 57%]\n...................................................... [100%]\n=============================== warnings summary ===============================\ntests/test_auth.py::test_jwt_authenticator_rejects_wrong_signature_and_hs256\n /tmp/hfact-attempt-20260910/approval-engine/.venv/lib/python3.12/site-packages/jwt/api_jwt.py:147: InsecureKeyLengthWarning: The HMAC key is 14 bytes long, which is below the minimum recommended length of 32 bytes for SHA256. See RFC 7518 Section 3.2.\n return self._jws.encode(\n\n-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html\n126 passed, 1 warning in 3.06s",
"mutation": {
"change": "canonical_binding returns the whole supplied input instead of only the act",
"result": "expected test failure",
"exit_code": 1,
"production_mutation_retained": false
},
"native_algorithm_changed": false,
"live_approval_issued": false,
"residuals": {
"consumer_adoption": "INFD-IN-0004 / INFD-WP-0001",
"human_control_enforcement": "APPROVAL-WP-0002-T01 / GH-DEC-2026-016",
"deployment_and_native_consumption": "APPROVAL-WP-0002-T03/T05"
}
}