Publish the valid-but-unbound claim; the missing shape was confounded
The example set satisfied §11's both-shapes clause only by accident. Both values of pdp_digest and pdp_path appeared, but they appeared in perfect correlation with validity: claim.valid carried a digest with pdp_path true, claim.revoked carried null with pdp_path false, and nothing else existed. Two independent dimensions presented as one. A reader could reasonably conclude that pdp_digest is null because the claim is revoked, or that pdp_path tracks validity. Both are false, and the example set is what would have taught them -- the failure the both-shapes clause exists to catch, which this repo proposed and then shipped a case of. The missing shape is the consequential one: a claim that is entirely valid -- valid_now true, reason_code ok, not consumed -- and carries no PDP binding. It is usable for a consumer comparing the native binding.digest and unusable on the GH-DEC-2026-003 path, where a PEP MUST refuse it. valid_now true is not permission to proceed on that lane. A consumer writing that refusal previously had no published shape to test against and would have had to invent a fixture, which is the drift §12 names. examples/claim.valid.no-pdp.json publishes it. The tests now assert the decorrelation rather than mere presence: one requires a valid claim with no PDP binding to exist, the other requires valid claims to cover both pdp_path declarations. Verified both fail when the new example is removed, so they hold the property rather than restating today's file list. 121 tests pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PM5HnEAhokxdfcPqBNpT7D Assistant: claude-code Assistant-Model: opus Assistant-Process: 715850@bnt-lap001 Assistant-Session: eb557e93-7cb1-45d0-9e57-7d15b3edc60e
This commit is contained in:
parent
119359c33d
commit
d5d1e41035
3 changed files with 99 additions and 2 deletions
|
|
@ -272,5 +272,25 @@ Local fixtures, workplan ids, and prose are not this claim.
|
|||
|
||||
## Examples
|
||||
|
||||
See [`../examples/claim.valid.json`](../examples/claim.valid.json) and
|
||||
[`../examples/claim.revoked.json`](../examples/claim.revoked.json).
|
||||
| Example | Shape it publishes |
|
||||
| --- | --- |
|
||||
| [`claim.valid.json`](../examples/claim.valid.json) | valid, on the PDP path — `pdp_path: true`, `pdp_digest` non-null |
|
||||
| [`claim.valid.no-pdp.json`](../examples/claim.valid.no-pdp.json) | **valid, with no PDP binding** — `valid_now: true`, `reason_code: ok`, `pdp_path: false`, `pdp_digest: null` |
|
||||
| [`claim.revoked.json`](../examples/claim.revoked.json) | revoked — `valid_now: false`, `reason_code: revoked` |
|
||||
|
||||
The middle one is the shape most likely to be missing from a consumer's tests,
|
||||
and it is the one that matters most on a privileged lane: the approval is
|
||||
genuinely valid and genuinely usable — for a consumer comparing the native
|
||||
`binding.digest` — while being **unusable on the `GH-DEC-2026-003` path**, where
|
||||
a PEP MUST refuse it. `valid_now: true` is not permission to proceed on that
|
||||
lane.
|
||||
|
||||
It is published because the first two examples alone would confound two
|
||||
independent dimensions. With only a valid claim carrying a digest and a revoked
|
||||
claim carrying none, a reader can reasonably infer that `pdp_digest` is null
|
||||
*because* the claim is revoked, or that `pdp_path` tracks validity. Both are
|
||||
false, and the example set is what would have taught them — the failure
|
||||
`security-layer-model` §11's both-shapes clause exists to catch.
|
||||
|
||||
`tests/test_examples.py` asserts the decorrelation, not merely that both values
|
||||
appear somewhere.
|
||||
|
|
|
|||
33
examples/claim.valid.no-pdp.json
Normal file
33
examples/claim.valid.no-pdp.json
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"schema_version": "0.1",
|
||||
"kind": "approval-claim",
|
||||
"yields_to": "net-kingdom taxonomy request-claim schema (statute §17; unassigned)",
|
||||
"issuer": "approval-engine",
|
||||
"approval_id": "7c4e2b91-08da-4f63-b5c7-2a9e6d1f04b3",
|
||||
"state": "valid",
|
||||
"valid_now": true,
|
||||
"consumed": false,
|
||||
"binding": {
|
||||
"action": "release.publish",
|
||||
"target": {
|
||||
"id": "svc-approval-engine",
|
||||
"stage": "prod"
|
||||
},
|
||||
"actor": "agt-release-runner",
|
||||
"principal": "bernd",
|
||||
"purpose": "cut-0-1-0-release",
|
||||
"digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
||||
"pdp_digest": null,
|
||||
"pdp_path": false
|
||||
},
|
||||
"freshness": {
|
||||
"observed_at": "2026-08-29T12:00:00+00:00",
|
||||
"ttl_seconds": 30,
|
||||
"not_after": "2026-08-29T12:00:30+00:00"
|
||||
},
|
||||
"validity": {
|
||||
"not_before": "2026-08-29T11:00:00+00:00",
|
||||
"expires_at": "2026-08-29T15:00:00+00:00"
|
||||
},
|
||||
"reason_code": "ok"
|
||||
}
|
||||
|
|
@ -46,6 +46,50 @@ def test_examples_cover_both_pdp_path_declarations():
|
|||
assert states == {True, False}
|
||||
|
||||
|
||||
def test_pdp_binding_is_not_confounded_with_validity():
|
||||
"""Both shapes present is not enough if they only ever co-vary.
|
||||
|
||||
With only `claim.valid` (pdp_digest set, pdp_path true) and `claim.revoked`
|
||||
(null, false), the two dimensions are perfectly correlated and an
|
||||
implementer can reasonably infer that pdp_digest is null *because* the claim
|
||||
is revoked, or that pdp_path tracks validity. Both inferences are wrong and
|
||||
the example set is what teaches them.
|
||||
|
||||
The shape that must exist is a claim that is entirely valid -- `valid_now`
|
||||
true, `reason_code` ok, not consumed -- and still carries no PDP binding.
|
||||
That is the claim a privileged-lane PEP MUST refuse under
|
||||
`GH-DEC-2026-008`, and it is the one a consumer would otherwise have to
|
||||
invent a fixture for.
|
||||
"""
|
||||
claims = [json.loads(p.read_text()) for p in EXAMPLES]
|
||||
valid_without_pdp = [
|
||||
c
|
||||
for c in claims
|
||||
if c["valid_now"]
|
||||
and c["reason_code"] == "ok"
|
||||
and not c["consumed"]
|
||||
and c["binding"]["pdp_digest"] is None
|
||||
and c["binding"]["pdp_path"] is False
|
||||
]
|
||||
assert valid_without_pdp, (
|
||||
"no example of a valid claim with no PDP binding; a consumer writing the "
|
||||
"privileged-lane refusal has no published shape to test against"
|
||||
)
|
||||
|
||||
|
||||
def test_valid_claims_cover_both_pdp_path_declarations():
|
||||
"""The decorrelation stated as coverage rather than as one instance."""
|
||||
paths = {
|
||||
c["binding"]["pdp_path"]
|
||||
for c in (json.loads(p.read_text()) for p in EXAMPLES)
|
||||
if c["valid_now"]
|
||||
}
|
||||
assert paths == {True, False}, (
|
||||
f"valid examples declare only pdp_path={paths}; both are reachable states "
|
||||
"for a valid approval"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("path", EXAMPLES, ids=lambda p: p.name)
|
||||
def test_pdp_path_examples_always_carry_a_digest(path):
|
||||
"""GH-DEC-2026-008: pdp_path true guarantees pdp_digest non-null."""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue