From ad7b7f536a0c7ab0b9b5173edc08cfc21f652d09 Mon Sep 17 00:00:00 2001 From: tegwick Date: Mon, 21 Sep 2026 23:06:40 +0200 Subject: [PATCH] Admit list for the informed-decision overview as compact-sitting v3 (FLEX-DEC-2026-017). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit list is a separate rule with exact-record scope over the union of the eight sitting records and the three T03 records, each pinned by approval id, digest and its own memo version, with a 12-hour MFA window. read and the five acts keep the v2 rule unchanged — same eight records, same 900-second window — so a list allow satisfies nothing else. The operator chose exact-record scope over the consumer's preferred type-wide scope: the PDP checks no recipient, so type-wide scope with a relaxed window would have left the consumer's structural match — which the consumer itself says is not an entitlement — as the only scope. The 12-hour bound replaces the requested "no bound" so the PDP still states one. The KeyCape stale-timestamp defect is not worked around; read stays strict. 417 evaluator checks: 168 v2 unchanged, 231 list, 18 proving no act widens to the T03 records. Also fixes tools/exercise_t03_review_policy.py, which had been failing since f85479c moved the T03 records to memo version 2 and it still sent version 1. Test-only. Not deployed: the pin serving the live review surface changes only with operator confirmation. Co-Authored-By: Claude Opus 5 Assistant: claude-code Assistant-Model: opus Assistant-Process: 28468@bnt-lap001 Assistant-Session: c76569b2-6056-4dad-aea4-49cd7a018f5d --- decisions/decisions.md | 57 + .../2026-09-21-sitting-review-policy-v3.json | 1673 +++++++++++++++++ .../list_only_records.json | 20 + examples/informed-decision-sitting/policy.md | 85 +- tools/exercise_sitting_review_policy.py | 71 + tools/exercise_t03_review_policy.py | 4 +- ...X-WP-0032-informed-decision-list-action.md | 26 +- 7 files changed, 1928 insertions(+), 8 deletions(-) create mode 100644 docs/evidence/2026-09-21-sitting-review-policy-v3.json create mode 100644 examples/informed-decision-sitting/list_only_records.json diff --git a/decisions/decisions.md b/decisions/decisions.md index aa42175..d595c02 100644 --- a/decisions/decisions.md +++ b/decisions/decisions.md @@ -1953,3 +1953,60 @@ denies (mismatch, absent) were added. 42 fixtures, 33 embedded tests, all pass. of behaviour for any caller that is not tenant-engine; per `FLEX-DEC-2026-008` it is a version change, not a silent edit. tenant-engine asked for no notice period. + +## FLEX-DEC-2026-017 — `informed-decision.compact-sitting` v3 admits `list`: exact-record scope, 12-hour MFA window, acts unchanged + +**Status:** accepted — operator decision, 2026-09-21 +**Requested by:** `informed-decision` (`INFD-IN-0008`, `INFD-WP-0004-T02`), +hub message `a7b9ef3b-f95c-4c50-bfc5-7628d16881f6` +**Workplan:** `FLEX-WP-0032` +**Package:** `informed-decision.compact-sitting` v3, +`sha256:dd40c80c5719851737178097cdee65afac108b54e19c07370e549b860f1a9655` + +**Decision.** v3 adds one action, `list`, as a rule of its own. It is not a +seventh member of the act set, and it changes nothing that v2 decided. + +1. **Acts unchanged.** `read`, `acknowledge`, `accept`, `return`, `discuss` and + `decline` keep the v2 rule unchanged: the same eight records, the same + 900-second MFA window. A `list` allow satisfies no other action. +2. **Exact-record scope.** `list` ranges over the union of this package's eight + records and the three `SECRETS-WP-0010-T03-*` records from + `informed-decision.t03-review`, each pinned by approval id, binding digest + and its own memo version (T03 at 2, sitting at 1). +3. **A lighter bar, not an absent one.** `list` requires the same identity as + the acts with a **12-hour** MFA window instead of 900 seconds. + +**Why exact-record over resource-type-wide.** The consumer preferred +resource-type-wide scope (option A). The v2 rule scopes a decision three ways — +exact-record pinning, group, fresh MFA — and checks no recipient. Option A, +together with a relaxed window, would have removed both PDP-side scopes for +`list` at once, leaving the consumer's structural recipient match as the only +thing between a group member and every memo's question and status. The +consumer's own request says that match "is not an entitlement." A PDP cannot +rest an allow on a check its consumer disclaims. Under exact-record scope a memo +becomes listable when someone admits it, and a package version per sitting is +the cost of that property. + +**Why a bound at all.** The request asked for no freshness bound. Unbounded +would have let an MFA of any age satisfy `list` for as long as the consumer +presented a key-cape session, and the PDP would have stated nothing. Twelve +hours covers the observed production refusals (1744 s) with ample margin and +keeps the bound in the policy, where a reviewer can read it. + +**What this does not do.** It does not work around the KeyCape stale-timestamp +defect (`INFD-IN-0005`), which made the overview fail in the first place. The +case for `list` stands on its own — looking back at your own outcomes is not +binding a new one — and `read` stays strict. Loosening a binding bar to absorb +an identity-layer fault would move key-cape's defect into flex-auth's policy. + +**Evidence.** 417 evaluator checks +(`docs/evidence/2026-09-21-sitting-review-policy-v3.json`): the 168 v2 checks +unchanged; 231 `list` checks over the 11-record union, including the observed +1744 s case allowed, the 12-hour bound refused past it, and stale MFA still +refused for `read`; and 18 proving no act widens to the T03 records even with +fresh MFA. Rego tests assert the union is exact and that T03 records are outside +the act scope. T03's own 57 checks pass. + +**Rollout.** Deploying v3 changes the pin serving a live human-review surface, +and is confirmed with the operator before it runs. informed-decision updates its +admission input to the version and digest above once the pin serves v3. diff --git a/docs/evidence/2026-09-21-sitting-review-policy-v3.json b/docs/evidence/2026-09-21-sitting-review-policy-v3.json new file mode 100644 index 0000000..8388340 --- /dev/null +++ b/docs/evidence/2026-09-21-sitting-review-policy-v3.json @@ -0,0 +1,1673 @@ +{ + "scope": "local actual evaluator with synthetic identity; no live human approvals; T03 package untouched", + "checks": [ + { + "check": "c02:read", + "effect": "allow" + }, + { + "check": "c02:acknowledge", + "effect": "allow" + }, + { + "check": "c02:accept", + "effect": "allow" + }, + { + "check": "c02:return", + "effect": "allow" + }, + { + "check": "c02:discuss", + "effect": "allow" + }, + { + "check": "c02:decline", + "effect": "allow" + }, + { + "check": "c02:wrong-group", + "effect": "deny" + }, + { + "check": "c02:no-group", + "effect": "deny" + }, + { + "check": "c02:service", + "effect": "deny" + }, + { + "check": "c02:stale-mfa", + "effect": "deny" + }, + { + "check": "c02:future-mfa", + "effect": "deny" + }, + { + "check": "c02:no-mfa", + "effect": "deny" + }, + { + "check": "c02:forged-human-route", + "effect": "deny" + }, + { + "check": "c02:wrong-tenant", + "effect": "deny" + }, + { + "check": "c02:other-memo", + "effect": "deny" + }, + { + "check": "c02:omitted-c01", + "effect": "deny" + }, + { + "check": "c02:t03-memo", + "effect": "deny" + }, + { + "check": "c02:changed-version", + "effect": "deny" + }, + { + "check": "c02:changed-approval", + "effect": "deny" + }, + { + "check": "c02:changed-digest", + "effect": "deny" + }, + { + "check": "c02:consume", + "effect": "deny" + }, + { + "check": "c03:read", + "effect": "allow" + }, + { + "check": "c03:acknowledge", + "effect": "allow" + }, + { + "check": "c03:accept", + "effect": "allow" + }, + { + "check": "c03:return", + "effect": "allow" + }, + { + "check": "c03:discuss", + "effect": "allow" + }, + { + "check": "c03:decline", + "effect": "allow" + }, + { + "check": "c03:wrong-group", + "effect": "deny" + }, + { + "check": "c03:no-group", + "effect": "deny" + }, + { + "check": "c03:service", + "effect": "deny" + }, + { + "check": "c03:stale-mfa", + "effect": "deny" + }, + { + "check": "c03:future-mfa", + "effect": "deny" + }, + { + "check": "c03:no-mfa", + "effect": "deny" + }, + { + "check": "c03:forged-human-route", + "effect": "deny" + }, + { + "check": "c03:wrong-tenant", + "effect": "deny" + }, + { + "check": "c03:other-memo", + "effect": "deny" + }, + { + "check": "c03:omitted-c01", + "effect": "deny" + }, + { + "check": "c03:t03-memo", + "effect": "deny" + }, + { + "check": "c03:changed-version", + "effect": "deny" + }, + { + "check": "c03:changed-approval", + "effect": "deny" + }, + { + "check": "c03:changed-digest", + "effect": "deny" + }, + { + "check": "c03:consume", + "effect": "deny" + }, + { + "check": "c04:read", + "effect": "allow" + }, + { + "check": "c04:acknowledge", + "effect": "allow" + }, + { + "check": "c04:accept", + "effect": "allow" + }, + { + "check": "c04:return", + "effect": "allow" + }, + { + "check": "c04:discuss", + "effect": "allow" + }, + { + "check": "c04:decline", + "effect": "allow" + }, + { + "check": "c04:wrong-group", + "effect": "deny" + }, + { + "check": "c04:no-group", + "effect": "deny" + }, + { + "check": "c04:service", + "effect": "deny" + }, + { + "check": "c04:stale-mfa", + "effect": "deny" + }, + { + "check": "c04:future-mfa", + "effect": "deny" + }, + { + "check": "c04:no-mfa", + "effect": "deny" + }, + { + "check": "c04:forged-human-route", + "effect": "deny" + }, + { + "check": "c04:wrong-tenant", + "effect": "deny" + }, + { + "check": "c04:other-memo", + "effect": "deny" + }, + { + "check": "c04:omitted-c01", + "effect": "deny" + }, + { + "check": "c04:t03-memo", + "effect": "deny" + }, + { + "check": "c04:changed-version", + "effect": "deny" + }, + { + "check": "c04:changed-approval", + "effect": "deny" + }, + { + "check": "c04:changed-digest", + "effect": "deny" + }, + { + "check": "c04:consume", + "effect": "deny" + }, + { + "check": "d01:read", + "effect": "allow" + }, + { + "check": "d01:acknowledge", + "effect": "allow" + }, + { + "check": "d01:accept", + "effect": "allow" + }, + { + "check": "d01:return", + "effect": "allow" + }, + { + "check": "d01:discuss", + "effect": "allow" + }, + { + "check": "d01:decline", + "effect": "allow" + }, + { + "check": "d01:wrong-group", + "effect": "deny" + }, + { + "check": "d01:no-group", + "effect": "deny" + }, + { + "check": "d01:service", + "effect": "deny" + }, + { + "check": "d01:stale-mfa", + "effect": "deny" + }, + { + "check": "d01:future-mfa", + "effect": "deny" + }, + { + "check": "d01:no-mfa", + "effect": "deny" + }, + { + "check": "d01:forged-human-route", + "effect": "deny" + }, + { + "check": "d01:wrong-tenant", + "effect": "deny" + }, + { + "check": "d01:other-memo", + "effect": "deny" + }, + { + "check": "d01:omitted-c01", + "effect": "deny" + }, + { + "check": "d01:t03-memo", + "effect": "deny" + }, + { + "check": "d01:changed-version", + "effect": "deny" + }, + { + "check": "d01:changed-approval", + "effect": "deny" + }, + { + "check": "d01:changed-digest", + "effect": "deny" + }, + { + "check": "d01:consume", + "effect": "deny" + }, + { + "check": "d02:read", + "effect": "allow" + }, + { + "check": "d02:acknowledge", + "effect": "allow" + }, + { + "check": "d02:accept", + "effect": "allow" + }, + { + "check": "d02:return", + "effect": "allow" + }, + { + "check": "d02:discuss", + "effect": "allow" + }, + { + "check": "d02:decline", + "effect": "allow" + }, + { + "check": "d02:wrong-group", + "effect": "deny" + }, + { + "check": "d02:no-group", + "effect": "deny" + }, + { + "check": "d02:service", + "effect": "deny" + }, + { + "check": "d02:stale-mfa", + "effect": "deny" + }, + { + "check": "d02:future-mfa", + "effect": "deny" + }, + { + "check": "d02:no-mfa", + "effect": "deny" + }, + { + "check": "d02:forged-human-route", + "effect": "deny" + }, + { + "check": "d02:wrong-tenant", + "effect": "deny" + }, + { + "check": "d02:other-memo", + "effect": "deny" + }, + { + "check": "d02:omitted-c01", + "effect": "deny" + }, + { + "check": "d02:t03-memo", + "effect": "deny" + }, + { + "check": "d02:changed-version", + "effect": "deny" + }, + { + "check": "d02:changed-approval", + "effect": "deny" + }, + { + "check": "d02:changed-digest", + "effect": "deny" + }, + { + "check": "d02:consume", + "effect": "deny" + }, + { + "check": "d03:read", + "effect": "allow" + }, + { + "check": "d03:acknowledge", + "effect": "allow" + }, + { + "check": "d03:accept", + "effect": "allow" + }, + { + "check": "d03:return", + "effect": "allow" + }, + { + "check": "d03:discuss", + "effect": "allow" + }, + { + "check": "d03:decline", + "effect": "allow" + }, + { + "check": "d03:wrong-group", + "effect": "deny" + }, + { + "check": "d03:no-group", + "effect": "deny" + }, + { + "check": "d03:service", + "effect": "deny" + }, + { + "check": "d03:stale-mfa", + "effect": "deny" + }, + { + "check": "d03:future-mfa", + "effect": "deny" + }, + { + "check": "d03:no-mfa", + "effect": "deny" + }, + { + "check": "d03:forged-human-route", + "effect": "deny" + }, + { + "check": "d03:wrong-tenant", + "effect": "deny" + }, + { + "check": "d03:other-memo", + "effect": "deny" + }, + { + "check": "d03:omitted-c01", + "effect": "deny" + }, + { + "check": "d03:t03-memo", + "effect": "deny" + }, + { + "check": "d03:changed-version", + "effect": "deny" + }, + { + "check": "d03:changed-approval", + "effect": "deny" + }, + { + "check": "d03:changed-digest", + "effect": "deny" + }, + { + "check": "d03:consume", + "effect": "deny" + }, + { + "check": "d04:read", + "effect": "allow" + }, + { + "check": "d04:acknowledge", + "effect": "allow" + }, + { + "check": "d04:accept", + "effect": "allow" + }, + { + "check": "d04:return", + "effect": "allow" + }, + { + "check": "d04:discuss", + "effect": "allow" + }, + { + "check": "d04:decline", + "effect": "allow" + }, + { + "check": "d04:wrong-group", + "effect": "deny" + }, + { + "check": "d04:no-group", + "effect": "deny" + }, + { + "check": "d04:service", + "effect": "deny" + }, + { + "check": "d04:stale-mfa", + "effect": "deny" + }, + { + "check": "d04:future-mfa", + "effect": "deny" + }, + { + "check": "d04:no-mfa", + "effect": "deny" + }, + { + "check": "d04:forged-human-route", + "effect": "deny" + }, + { + "check": "d04:wrong-tenant", + "effect": "deny" + }, + { + "check": "d04:other-memo", + "effect": "deny" + }, + { + "check": "d04:omitted-c01", + "effect": "deny" + }, + { + "check": "d04:t03-memo", + "effect": "deny" + }, + { + "check": "d04:changed-version", + "effect": "deny" + }, + { + "check": "d04:changed-approval", + "effect": "deny" + }, + { + "check": "d04:changed-digest", + "effect": "deny" + }, + { + "check": "d04:consume", + "effect": "deny" + }, + { + "check": "b01:read", + "effect": "allow" + }, + { + "check": "b01:acknowledge", + "effect": "allow" + }, + { + "check": "b01:accept", + "effect": "allow" + }, + { + "check": "b01:return", + "effect": "allow" + }, + { + "check": "b01:discuss", + "effect": "allow" + }, + { + "check": "b01:decline", + "effect": "allow" + }, + { + "check": "b01:wrong-group", + "effect": "deny" + }, + { + "check": "b01:no-group", + "effect": "deny" + }, + { + "check": "b01:service", + "effect": "deny" + }, + { + "check": "b01:stale-mfa", + "effect": "deny" + }, + { + "check": "b01:future-mfa", + "effect": "deny" + }, + { + "check": "b01:no-mfa", + "effect": "deny" + }, + { + "check": "b01:forged-human-route", + "effect": "deny" + }, + { + "check": "b01:wrong-tenant", + "effect": "deny" + }, + { + "check": "b01:other-memo", + "effect": "deny" + }, + { + "check": "b01:omitted-c01", + "effect": "deny" + }, + { + "check": "b01:t03-memo", + "effect": "deny" + }, + { + "check": "b01:changed-version", + "effect": "deny" + }, + { + "check": "b01:changed-approval", + "effect": "deny" + }, + { + "check": "b01:changed-digest", + "effect": "deny" + }, + { + "check": "b01:consume", + "effect": "deny" + }, + { + "check": "list:c02:fresh", + "effect": "allow" + }, + { + "check": "list:c02:observed-1744s", + "effect": "allow" + }, + { + "check": "list:c02:inside-12h", + "effect": "allow" + }, + { + "check": "list:c02:past-12h", + "effect": "deny" + }, + { + "check": "list:c02:read-stale-refused", + "effect": "deny" + }, + { + "check": "list:c02:wrong-group", + "effect": "deny" + }, + { + "check": "list:c02:no-group", + "effect": "deny" + }, + { + "check": "list:c02:service", + "effect": "deny" + }, + { + "check": "list:c02:agent", + "effect": "deny" + }, + { + "check": "list:c02:future-mfa", + "effect": "deny" + }, + { + "check": "list:c02:no-mfa", + "effect": "deny" + }, + { + "check": "list:c02:aal1", + "effect": "deny" + }, + { + "check": "list:c02:forged-human-route", + "effect": "deny" + }, + { + "check": "list:c02:indeterminate-route", + "effect": "deny" + }, + { + "check": "list:c02:wrong-tenant", + "effect": "deny" + }, + { + "check": "list:c02:other-memo", + "effect": "deny" + }, + { + "check": "list:c02:omitted-c01", + "effect": "deny" + }, + { + "check": "list:c02:other-system", + "effect": "deny" + }, + { + "check": "list:c02:changed-version", + "effect": "deny" + }, + { + "check": "list:c02:changed-approval", + "effect": "deny" + }, + { + "check": "list:c02:changed-digest", + "effect": "deny" + }, + { + "check": "list:c03:fresh", + "effect": "allow" + }, + { + "check": "list:c03:observed-1744s", + "effect": "allow" + }, + { + "check": "list:c03:inside-12h", + "effect": "allow" + }, + { + "check": "list:c03:past-12h", + "effect": "deny" + }, + { + "check": "list:c03:read-stale-refused", + "effect": "deny" + }, + { + "check": "list:c03:wrong-group", + "effect": "deny" + }, + { + "check": "list:c03:no-group", + "effect": "deny" + }, + { + "check": "list:c03:service", + "effect": "deny" + }, + { + "check": "list:c03:agent", + "effect": "deny" + }, + { + "check": "list:c03:future-mfa", + "effect": "deny" + }, + { + "check": "list:c03:no-mfa", + "effect": "deny" + }, + { + "check": "list:c03:aal1", + "effect": "deny" + }, + { + "check": "list:c03:forged-human-route", + "effect": "deny" + }, + { + "check": "list:c03:indeterminate-route", + "effect": "deny" + }, + { + "check": "list:c03:wrong-tenant", + "effect": "deny" + }, + { + "check": "list:c03:other-memo", + "effect": "deny" + }, + { + "check": "list:c03:omitted-c01", + "effect": "deny" + }, + { + "check": "list:c03:other-system", + "effect": "deny" + }, + { + "check": "list:c03:changed-version", + "effect": "deny" + }, + { + "check": "list:c03:changed-approval", + "effect": "deny" + }, + { + "check": "list:c03:changed-digest", + "effect": "deny" + }, + { + "check": "list:c04:fresh", + "effect": "allow" + }, + { + "check": "list:c04:observed-1744s", + "effect": "allow" + }, + { + "check": "list:c04:inside-12h", + "effect": "allow" + }, + { + "check": "list:c04:past-12h", + "effect": "deny" + }, + { + "check": "list:c04:read-stale-refused", + "effect": "deny" + }, + { + "check": "list:c04:wrong-group", + "effect": "deny" + }, + { + "check": "list:c04:no-group", + "effect": "deny" + }, + { + "check": "list:c04:service", + "effect": "deny" + }, + { + "check": "list:c04:agent", + "effect": "deny" + }, + { + "check": "list:c04:future-mfa", + "effect": "deny" + }, + { + "check": "list:c04:no-mfa", + "effect": "deny" + }, + { + "check": "list:c04:aal1", + "effect": "deny" + }, + { + "check": "list:c04:forged-human-route", + "effect": "deny" + }, + { + "check": "list:c04:indeterminate-route", + "effect": "deny" + }, + { + "check": "list:c04:wrong-tenant", + "effect": "deny" + }, + { + "check": "list:c04:other-memo", + "effect": "deny" + }, + { + "check": "list:c04:omitted-c01", + "effect": "deny" + }, + { + "check": "list:c04:other-system", + "effect": "deny" + }, + { + "check": "list:c04:changed-version", + "effect": "deny" + }, + { + "check": "list:c04:changed-approval", + "effect": "deny" + }, + { + "check": "list:c04:changed-digest", + "effect": "deny" + }, + { + "check": "list:d01:fresh", + "effect": "allow" + }, + { + "check": "list:d01:observed-1744s", + "effect": "allow" + }, + { + "check": "list:d01:inside-12h", + "effect": "allow" + }, + { + "check": "list:d01:past-12h", + "effect": "deny" + }, + { + "check": "list:d01:read-stale-refused", + "effect": "deny" + }, + { + "check": "list:d01:wrong-group", + "effect": "deny" + }, + { + "check": "list:d01:no-group", + "effect": "deny" + }, + { + "check": "list:d01:service", + "effect": "deny" + }, + { + "check": "list:d01:agent", + "effect": "deny" + }, + { + "check": "list:d01:future-mfa", + "effect": "deny" + }, + { + "check": "list:d01:no-mfa", + "effect": "deny" + }, + { + "check": "list:d01:aal1", + "effect": "deny" + }, + { + "check": "list:d01:forged-human-route", + "effect": "deny" + }, + { + "check": "list:d01:indeterminate-route", + "effect": "deny" + }, + { + "check": "list:d01:wrong-tenant", + "effect": "deny" + }, + { + "check": "list:d01:other-memo", + "effect": "deny" + }, + { + "check": "list:d01:omitted-c01", + "effect": "deny" + }, + { + "check": "list:d01:other-system", + "effect": "deny" + }, + { + "check": "list:d01:changed-version", + "effect": "deny" + }, + { + "check": "list:d01:changed-approval", + "effect": "deny" + }, + { + "check": "list:d01:changed-digest", + "effect": "deny" + }, + { + "check": "list:d02:fresh", + "effect": "allow" + }, + { + "check": "list:d02:observed-1744s", + "effect": "allow" + }, + { + "check": "list:d02:inside-12h", + "effect": "allow" + }, + { + "check": "list:d02:past-12h", + "effect": "deny" + }, + { + "check": "list:d02:read-stale-refused", + "effect": "deny" + }, + { + "check": "list:d02:wrong-group", + "effect": "deny" + }, + { + "check": "list:d02:no-group", + "effect": "deny" + }, + { + "check": "list:d02:service", + "effect": "deny" + }, + { + "check": "list:d02:agent", + "effect": "deny" + }, + { + "check": "list:d02:future-mfa", + "effect": "deny" + }, + { + "check": "list:d02:no-mfa", + "effect": "deny" + }, + { + "check": "list:d02:aal1", + "effect": "deny" + }, + { + "check": "list:d02:forged-human-route", + "effect": "deny" + }, + { + "check": "list:d02:indeterminate-route", + "effect": "deny" + }, + { + "check": "list:d02:wrong-tenant", + "effect": "deny" + }, + { + "check": "list:d02:other-memo", + "effect": "deny" + }, + { + "check": "list:d02:omitted-c01", + "effect": "deny" + }, + { + "check": "list:d02:other-system", + "effect": "deny" + }, + { + "check": "list:d02:changed-version", + "effect": "deny" + }, + { + "check": "list:d02:changed-approval", + "effect": "deny" + }, + { + "check": "list:d02:changed-digest", + "effect": "deny" + }, + { + "check": "list:d03:fresh", + "effect": "allow" + }, + { + "check": "list:d03:observed-1744s", + "effect": "allow" + }, + { + "check": "list:d03:inside-12h", + "effect": "allow" + }, + { + "check": "list:d03:past-12h", + "effect": "deny" + }, + { + "check": "list:d03:read-stale-refused", + "effect": "deny" + }, + { + "check": "list:d03:wrong-group", + "effect": "deny" + }, + { + "check": "list:d03:no-group", + "effect": "deny" + }, + { + "check": "list:d03:service", + "effect": "deny" + }, + { + "check": "list:d03:agent", + "effect": "deny" + }, + { + "check": "list:d03:future-mfa", + "effect": "deny" + }, + { + "check": "list:d03:no-mfa", + "effect": "deny" + }, + { + "check": "list:d03:aal1", + "effect": "deny" + }, + { + "check": "list:d03:forged-human-route", + "effect": "deny" + }, + { + "check": "list:d03:indeterminate-route", + "effect": "deny" + }, + { + "check": "list:d03:wrong-tenant", + "effect": "deny" + }, + { + "check": "list:d03:other-memo", + "effect": "deny" + }, + { + "check": "list:d03:omitted-c01", + "effect": "deny" + }, + { + "check": "list:d03:other-system", + "effect": "deny" + }, + { + "check": "list:d03:changed-version", + "effect": "deny" + }, + { + "check": "list:d03:changed-approval", + "effect": "deny" + }, + { + "check": "list:d03:changed-digest", + "effect": "deny" + }, + { + "check": "list:d04:fresh", + "effect": "allow" + }, + { + "check": "list:d04:observed-1744s", + "effect": "allow" + }, + { + "check": "list:d04:inside-12h", + "effect": "allow" + }, + { + "check": "list:d04:past-12h", + "effect": "deny" + }, + { + "check": "list:d04:read-stale-refused", + "effect": "deny" + }, + { + "check": "list:d04:wrong-group", + "effect": "deny" + }, + { + "check": "list:d04:no-group", + "effect": "deny" + }, + { + "check": "list:d04:service", + "effect": "deny" + }, + { + "check": "list:d04:agent", + "effect": "deny" + }, + { + "check": "list:d04:future-mfa", + "effect": "deny" + }, + { + "check": "list:d04:no-mfa", + "effect": "deny" + }, + { + "check": "list:d04:aal1", + "effect": "deny" + }, + { + "check": "list:d04:forged-human-route", + "effect": "deny" + }, + { + "check": "list:d04:indeterminate-route", + "effect": "deny" + }, + { + "check": "list:d04:wrong-tenant", + "effect": "deny" + }, + { + "check": "list:d04:other-memo", + "effect": "deny" + }, + { + "check": "list:d04:omitted-c01", + "effect": "deny" + }, + { + "check": "list:d04:other-system", + "effect": "deny" + }, + { + "check": "list:d04:changed-version", + "effect": "deny" + }, + { + "check": "list:d04:changed-approval", + "effect": "deny" + }, + { + "check": "list:d04:changed-digest", + "effect": "deny" + }, + { + "check": "list:b01:fresh", + "effect": "allow" + }, + { + "check": "list:b01:observed-1744s", + "effect": "allow" + }, + { + "check": "list:b01:inside-12h", + "effect": "allow" + }, + { + "check": "list:b01:past-12h", + "effect": "deny" + }, + { + "check": "list:b01:read-stale-refused", + "effect": "deny" + }, + { + "check": "list:b01:wrong-group", + "effect": "deny" + }, + { + "check": "list:b01:no-group", + "effect": "deny" + }, + { + "check": "list:b01:service", + "effect": "deny" + }, + { + "check": "list:b01:agent", + "effect": "deny" + }, + { + "check": "list:b01:future-mfa", + "effect": "deny" + }, + { + "check": "list:b01:no-mfa", + "effect": "deny" + }, + { + "check": "list:b01:aal1", + "effect": "deny" + }, + { + "check": "list:b01:forged-human-route", + "effect": "deny" + }, + { + "check": "list:b01:indeterminate-route", + "effect": "deny" + }, + { + "check": "list:b01:wrong-tenant", + "effect": "deny" + }, + { + "check": "list:b01:other-memo", + "effect": "deny" + }, + { + "check": "list:b01:omitted-c01", + "effect": "deny" + }, + { + "check": "list:b01:other-system", + "effect": "deny" + }, + { + "check": "list:b01:changed-version", + "effect": "deny" + }, + { + "check": "list:b01:changed-approval", + "effect": "deny" + }, + { + "check": "list:b01:changed-digest", + "effect": "deny" + }, + { + "check": "list:t03-apply:fresh", + "effect": "allow" + }, + { + "check": "list:t03-apply:observed-1744s", + "effect": "allow" + }, + { + "check": "list:t03-apply:inside-12h", + "effect": "allow" + }, + { + "check": "list:t03-apply:past-12h", + "effect": "deny" + }, + { + "check": "list:t03-apply:read-stale-refused", + "effect": "deny" + }, + { + "check": "list:t03-apply:act-read-not-widened", + "effect": "deny" + }, + { + "check": "list:t03-apply:act-acknowledge-not-widened", + "effect": "deny" + }, + { + "check": "list:t03-apply:act-accept-not-widened", + "effect": "deny" + }, + { + "check": "list:t03-apply:act-return-not-widened", + "effect": "deny" + }, + { + "check": "list:t03-apply:act-discuss-not-widened", + "effect": "deny" + }, + { + "check": "list:t03-apply:act-decline-not-widened", + "effect": "deny" + }, + { + "check": "list:t03-apply:wrong-group", + "effect": "deny" + }, + { + "check": "list:t03-apply:no-group", + "effect": "deny" + }, + { + "check": "list:t03-apply:service", + "effect": "deny" + }, + { + "check": "list:t03-apply:agent", + "effect": "deny" + }, + { + "check": "list:t03-apply:future-mfa", + "effect": "deny" + }, + { + "check": "list:t03-apply:no-mfa", + "effect": "deny" + }, + { + "check": "list:t03-apply:aal1", + "effect": "deny" + }, + { + "check": "list:t03-apply:forged-human-route", + "effect": "deny" + }, + { + "check": "list:t03-apply:indeterminate-route", + "effect": "deny" + }, + { + "check": "list:t03-apply:wrong-tenant", + "effect": "deny" + }, + { + "check": "list:t03-apply:other-memo", + "effect": "deny" + }, + { + "check": "list:t03-apply:omitted-c01", + "effect": "deny" + }, + { + "check": "list:t03-apply:other-system", + "effect": "deny" + }, + { + "check": "list:t03-apply:changed-version", + "effect": "deny" + }, + { + "check": "list:t03-apply:changed-approval", + "effect": "deny" + }, + { + "check": "list:t03-apply:changed-digest", + "effect": "deny" + }, + { + "check": "list:t03-verify:fresh", + "effect": "allow" + }, + { + "check": "list:t03-verify:observed-1744s", + "effect": "allow" + }, + { + "check": "list:t03-verify:inside-12h", + "effect": "allow" + }, + { + "check": "list:t03-verify:past-12h", + "effect": "deny" + }, + { + "check": "list:t03-verify:read-stale-refused", + "effect": "deny" + }, + { + "check": "list:t03-verify:act-read-not-widened", + "effect": "deny" + }, + { + "check": "list:t03-verify:act-acknowledge-not-widened", + "effect": "deny" + }, + { + "check": "list:t03-verify:act-accept-not-widened", + "effect": "deny" + }, + { + "check": "list:t03-verify:act-return-not-widened", + "effect": "deny" + }, + { + "check": "list:t03-verify:act-discuss-not-widened", + "effect": "deny" + }, + { + "check": "list:t03-verify:act-decline-not-widened", + "effect": "deny" + }, + { + "check": "list:t03-verify:wrong-group", + "effect": "deny" + }, + { + "check": "list:t03-verify:no-group", + "effect": "deny" + }, + { + "check": "list:t03-verify:service", + "effect": "deny" + }, + { + "check": "list:t03-verify:agent", + "effect": "deny" + }, + { + "check": "list:t03-verify:future-mfa", + "effect": "deny" + }, + { + "check": "list:t03-verify:no-mfa", + "effect": "deny" + }, + { + "check": "list:t03-verify:aal1", + "effect": "deny" + }, + { + "check": "list:t03-verify:forged-human-route", + "effect": "deny" + }, + { + "check": "list:t03-verify:indeterminate-route", + "effect": "deny" + }, + { + "check": "list:t03-verify:wrong-tenant", + "effect": "deny" + }, + { + "check": "list:t03-verify:other-memo", + "effect": "deny" + }, + { + "check": "list:t03-verify:omitted-c01", + "effect": "deny" + }, + { + "check": "list:t03-verify:other-system", + "effect": "deny" + }, + { + "check": "list:t03-verify:changed-version", + "effect": "deny" + }, + { + "check": "list:t03-verify:changed-approval", + "effect": "deny" + }, + { + "check": "list:t03-verify:changed-digest", + "effect": "deny" + }, + { + "check": "list:t03-exec:fresh", + "effect": "allow" + }, + { + "check": "list:t03-exec:observed-1744s", + "effect": "allow" + }, + { + "check": "list:t03-exec:inside-12h", + "effect": "allow" + }, + { + "check": "list:t03-exec:past-12h", + "effect": "deny" + }, + { + "check": "list:t03-exec:read-stale-refused", + "effect": "deny" + }, + { + "check": "list:t03-exec:act-read-not-widened", + "effect": "deny" + }, + { + "check": "list:t03-exec:act-acknowledge-not-widened", + "effect": "deny" + }, + { + "check": "list:t03-exec:act-accept-not-widened", + "effect": "deny" + }, + { + "check": "list:t03-exec:act-return-not-widened", + "effect": "deny" + }, + { + "check": "list:t03-exec:act-discuss-not-widened", + "effect": "deny" + }, + { + "check": "list:t03-exec:act-decline-not-widened", + "effect": "deny" + }, + { + "check": "list:t03-exec:wrong-group", + "effect": "deny" + }, + { + "check": "list:t03-exec:no-group", + "effect": "deny" + }, + { + "check": "list:t03-exec:service", + "effect": "deny" + }, + { + "check": "list:t03-exec:agent", + "effect": "deny" + }, + { + "check": "list:t03-exec:future-mfa", + "effect": "deny" + }, + { + "check": "list:t03-exec:no-mfa", + "effect": "deny" + }, + { + "check": "list:t03-exec:aal1", + "effect": "deny" + }, + { + "check": "list:t03-exec:forged-human-route", + "effect": "deny" + }, + { + "check": "list:t03-exec:indeterminate-route", + "effect": "deny" + }, + { + "check": "list:t03-exec:wrong-tenant", + "effect": "deny" + }, + { + "check": "list:t03-exec:other-memo", + "effect": "deny" + }, + { + "check": "list:t03-exec:omitted-c01", + "effect": "deny" + }, + { + "check": "list:t03-exec:other-system", + "effect": "deny" + }, + { + "check": "list:t03-exec:changed-version", + "effect": "deny" + }, + { + "check": "list:t03-exec:changed-approval", + "effect": "deny" + }, + { + "check": "list:t03-exec:changed-digest", + "effect": "deny" + } + ] +} diff --git a/examples/informed-decision-sitting/list_only_records.json b/examples/informed-decision-sitting/list_only_records.json new file mode 100644 index 0000000..ec8644f --- /dev/null +++ b/examples/informed-decision-sitting/list_only_records.json @@ -0,0 +1,20 @@ +{ + "memo:SECRETS-WP-0010-T03-apply": { + "approval_id": "9935335c-8e9a-566e-a48e-6a5b5f4882eb", + "binding_digest": "sha256:03cc5b37437f14e86b686ce4054f976556334eff3fa260b03e8014ed3d9217e5", + "memo_version": 2, + "label": "t03-apply" + }, + "memo:SECRETS-WP-0010-T03-verify": { + "approval_id": "273d6882-6253-5dc9-ac54-544f92ef5e56", + "binding_digest": "sha256:72d9267d038c17107c880ffc9009793ce9c70defbddfe2219628854b811a04b2", + "memo_version": 2, + "label": "t03-verify" + }, + "memo:SECRETS-WP-0010-T03-exec": { + "approval_id": "7ba0c13b-68cd-5b3e-9481-42ba9e385e68", + "binding_digest": "sha256:f2cf0fb53b740900756ccde5587c3578fcff44beef2f1edab17b9a198a4033d8", + "memo_version": 2, + "label": "t03-exec" + } +} diff --git a/examples/informed-decision-sitting/policy.md b/examples/informed-decision-sitting/policy.md index d5c423f..291158a 100644 --- a/examples/informed-decision-sitting/policy.md +++ b/examples/informed-decision-sitting/policy.md @@ -2,11 +2,11 @@ id: informed-decision.compact-sitting name: Compact sitting exact-record human review namespace: informed-decision:decision-memo -version: v2 +version: v3 status: ready package: flexauth.informed_decision.compact_sitting allow_ttl: 30s -actions: [read, acknowledge, accept, return, discuss, decline] +actions: [read, acknowledge, accept, return, discuss, decline, list] owner: flex-auth fixtures: [fixtures.json] caring: @@ -26,6 +26,25 @@ and the identity bar are unchanged. It is not an expansion of `examples/informed-decision-t03` / FLEX-WP-0027. `memo:infd-20260914-c01` is omitted (create-client still undecided). +v3 (2026-09-21, `FLEX-WP-0032`, `FLEX-DEC-2026-017`) adds one action, `list`, +for informed-decision's decision overview (`INFD-IN-0008`). It is a separate +rule, not an extra member of the act set, and it changes nothing else: + +- `read` and the five acts keep the v2 rule unchanged — the same eight records, + the same 900-second MFA window. A `list` allow satisfies no other action. +- `list` covers the **union** of this package's eight records and the three + `SECRETS-WP-0010-T03-*` records from `informed-decision.t03-review`, each + pinned by approval id, binding digest and its own memo version (T03 at 2). + Scope stays exact-record: a memo is listable only once someone admitted it. + The operator declined resource-type-wide scope because the PDP checks no + recipient, and a type-wide rule would have left consumer code — which the + consumer itself says is not an entitlement — as the only scope. +- `list` carries the same identity bar with a **12-hour** MFA window instead of + 900 seconds. Looking back at your own outcomes is not binding a new one. The + bar is lighter, not absent: the PDP still states a bound. +- The KeyCape stale-timestamp defect (`INFD-IN-0005`) is **not** worked around + here. `read` stays strict; that defect is key-cape's to fix. + The identity bar matches T03: authenticated informed-decision caller, `net-kingdom-admins`, fresh KeyCape AAL2 MFA. No permission follows from memo content or presentation state. TokenReview must admit @@ -73,6 +92,31 @@ records := { } } +list_only_records := { + "memo:SECRETS-WP-0010-T03-apply": { + "approval_id": "9935335c-8e9a-566e-a48e-6a5b5f4882eb", + "binding_digest": "sha256:03cc5b37437f14e86b686ce4054f976556334eff3fa260b03e8014ed3d9217e5", + "memo_version": 2 + }, + "memo:SECRETS-WP-0010-T03-verify": { + "approval_id": "273d6882-6253-5dc9-ac54-544f92ef5e56", + "binding_digest": "sha256:72d9267d038c17107c880ffc9009793ce9c70defbddfe2219628854b811a04b2", + "memo_version": 2 + }, + "memo:SECRETS-WP-0010-T03-exec": { + "approval_id": "7ba0c13b-68cd-5b3e-9481-42ba9e385e68", + "binding_digest": "sha256:f2cf0fb53b740900756ccde5587c3578fcff44beef2f1edab17b9a198a4033d8", + "memo_version": 2 + } +} + +# listable is the union list may range over. Sitting records are memo version 1, +# as the act rule pins; T03 records carry their own version (2). +listable := object.union( + {id: object.union(r, {"memo_version": 1}) | some id, r in records}, + list_only_records, +) + decision := {"effect": "allow", "reason": "operator_admitted_compact_sitting"} if { input.tenant == "tenant:platform" input.subject.tenant == "tenant:platform" @@ -100,6 +144,33 @@ decision := {"effect": "allow", "reason": "operator_admitted_compact_sitting"} i input.context.approval_id == record.approval_id input.context.approval_binding_digest == record.binding_digest input.action in {"read", "acknowledge", "accept", "return", "discuss", "decline"} +} else := {"effect": "allow", "reason": "operator_admitted_overview_list"} if { + input.action == "list" + input.tenant == "tenant:platform" + input.subject.tenant == "tenant:platform" + input.subject.type == "human" + is_string(input.subject.id) + input.subject.id != "" + input.subject.attributes.principal_type_source == "authentication-derived" + input.subject.attributes.tenant_source in {"registration-supplied", "directory-asserted"} + "net-kingdom-admins" in input.subject.attributes.groups + assurance := input.subject.attributes.assurance + assurance.level == "aal2" + assurance.mfa == true + assurance.source == "key-cape" + assurance.methods == ["pwd", "otp"] + is_number(assurance.at) + assurance.at > 0 + age := time.now_ns() / 1000000000 - assurance.at + age >= -30 + age <= 43200 + input.resource.tenant == "tenant:platform" + input.resource.system == "informed-decision" + input.resource.type == "decision-memo" + record := listable[input.resource.id] + input.context.memo_version == record.memo_version + input.context.approval_id == record.approval_id + input.context.approval_binding_digest == record.binding_digest } else := {"effect": "deny", "reason": "compact_sitting_scope_or_identity_refused"} if { true } @@ -113,4 +184,14 @@ import data.flexauth.informed_decision.compact_sitting test_unknown_request_denied if { compact_sitting.decision.effect == "deny" with input as {} } + +test_listable_is_exact_union if { + count(compact_sitting.listable) == count(compact_sitting.records) + count(compact_sitting.list_only_records) +} + +test_t03_records_not_in_act_scope if { + every id, _ in compact_sitting.list_only_records { + not compact_sitting.records[id] + } +} ``` diff --git a/tools/exercise_sitting_review_policy.py b/tools/exercise_sitting_review_policy.py index 3390c56..bce6a86 100644 --- a/tools/exercise_sitting_review_policy.py +++ b/tools/exercise_sitting_review_policy.py @@ -87,6 +87,77 @@ with tempfile.TemporaryDirectory() as temp: target[path[-1]] = value check(label + ':' + name, candidate, 'deny') + # --- v3 list (FLEX-WP-0032, FLEX-DEC-2026-017) --------------------------- + # list ranges over the union of the act records and the list-only records; + # every act stays scoped to the act records, with the 900 s window. + list_only = json.loads((r / 'list_only_records.json').read_text()) + listable = {k: dict(v, memo_version=1) for k, v in records.items()} | list_only + now = int(time.time()) + for memo, record in listable.items(): + request = { + 'id': 'local-regression', + 'tenant': 'tenant:platform', + 'subject': { + 'id': 'synthetic-reviewer', 'type': 'human', 'tenant': 'tenant:platform', + 'attributes': { + 'groups': ['net-kingdom-admins'], 'roles': [], + 'tenant_source': 'registration-supplied', + 'principal_type_source': 'authentication-derived', + 'assurance': {'level': 'aal2', 'mfa': True, 'methods': ['pwd', 'otp'], + 'source': 'key-cape', 'at': now}, + }, + }, + 'resource': {'id': memo, 'type': 'decision-memo', + 'system': 'informed-decision', 'tenant': 'tenant:platform'}, + 'action': 'list', + 'context': {'memo_version': record['memo_version'], + 'approval_id': record['approval_id'], + 'approval_binding_digest': record['binding_digest']}, + } + label = 'list:' + record['label'] + + def variant(path, value, req=request): + c = copy.deepcopy(req) + t = c + for key in path[:-1]: + t = t[key] + t[path[-1]] = value + return c + + at = ['subject', 'attributes', 'assurance', 'at'] + check(label + ':fresh', request, 'allow') + # The observed production refusal: 1744 s, allowed for list... + check(label + ':observed-1744s', variant(at, now - 1744), 'allow') + check(label + ':inside-12h', variant(at, now - 43200 + 60), 'allow') + # ...but the 12 h bound is real, and read does not follow list. + check(label + ':past-12h', variant(at, now - 43200 - 60), 'deny') + is_act_record = memo in records + read_stale = variant(at, now - 1744) | {'action': 'read'} + check(label + ':read-stale-refused', read_stale, 'deny') + if not is_act_record: + # T03 records are listable only; no act widens to them, even fresh. + for action in ['read', 'acknowledge', 'accept', 'return', 'discuss', 'decline']: + check(label + ':act-' + action + '-not-widened', request | {'action': action}, 'deny') + for name, path, value in [ + ('wrong-group', ['subject', 'attributes', 'groups'], ['net-kingdom-users']), + ('no-group', ['subject', 'attributes', 'groups'], []), + ('service', ['subject', 'type'], 'service'), + ('agent', ['subject', 'type'], 'agent'), + ('future-mfa', at, now + 300), + ('no-mfa', ['subject', 'attributes', 'assurance', 'mfa'], False), + ('aal1', ['subject', 'attributes', 'assurance', 'level'], 'aal1'), + ('forged-human-route', ['subject', 'attributes', 'principal_type_source'], 'registration-supplied'), + ('indeterminate-route', ['subject', 'attributes', 'principal_type_source'], 'indeterminate'), + ('wrong-tenant', ['subject', 'tenant'], 'tenant:other'), + ('other-memo', ['resource', 'id'], 'memo:other'), + ('omitted-c01', ['resource', 'id'], 'memo:infd-20260914-c01'), + ('other-system', ['resource', 'system'], 'secrets-engine'), + ('changed-version', ['context', 'memo_version'], record['memo_version'] + 1), + ('changed-approval', ['context', 'approval_id'], 'other'), + ('changed-digest', ['context', 'approval_binding_digest'], 'sha256:' + '0' * 64), + ]: + check(label + ':' + name, variant(path, value), 'deny') + args.receipt.write_text(json.dumps({ 'scope': 'local actual evaluator with synthetic identity; no live human approvals; T03 package untouched', 'checks': results, diff --git a/tools/exercise_t03_review_policy.py b/tools/exercise_t03_review_policy.py index fd3cd0f..82080fa 100644 --- a/tools/exercise_t03_review_policy.py +++ b/tools/exercise_t03_review_policy.py @@ -15,10 +15,10 @@ with tempfile.TemporaryDirectory() as temp: results.append({'check':name,'effect':d['effect']}) return d for memo,record in records.items(): - request={'id':'local-regression','tenant':'tenant:platform','subject':{'id':'synthetic-reviewer','type':'human','tenant':'tenant:platform','attributes':{'groups':['net-kingdom-admins'],'roles':[],'tenant_source':'registration-supplied','principal_type_source':'authentication-derived','assurance':{'level':'aal2','mfa':True,'methods':['pwd','otp'],'source':'key-cape','at':int(time.time())}}},'resource':{'id':memo,'type':'decision-memo','system':'informed-decision','tenant':'tenant:platform'},'action':'accept','context':{'memo_version':1,'approval_id':record['approval_id'],'approval_binding_digest':record['binding_digest']},'policy_version':'v1'} + request={'id':'local-regression','tenant':'tenant:platform','subject':{'id':'synthetic-reviewer','type':'human','tenant':'tenant:platform','attributes':{'groups':['net-kingdom-admins'],'roles':[],'tenant_source':'registration-supplied','principal_type_source':'authentication-derived','assurance':{'level':'aal2','mfa':True,'methods':['pwd','otp'],'source':'key-cape','at':int(time.time())}}},'resource':{'id':memo,'type':'decision-memo','system':'informed-decision','tenant':'tenant:platform'},'action':'accept','context':{'memo_version':record['memo_version'],'approval_id':record['approval_id'],'approval_binding_digest':record['binding_digest']},'policy_version':'v1'} for action in ['read','acknowledge','accept','return','discuss','decline']: d=check(record['action']+':'+action,request|{'action':action},'allow') - for name,path,value in [('wrong-group',['subject','attributes','groups'],['net-kingdom-users']),('no-group',['subject','attributes','groups'],[]),('service',['subject','type'],'service'),('stale-mfa',['subject','attributes','assurance','at'],int(time.time())-901),('future-mfa',['subject','attributes','assurance','at'],int(time.time())+300),('no-mfa',['subject','attributes','assurance','mfa'],False),('forged-human-route',['subject','attributes','principal_type_source'],'registration-supplied'),('wrong-tenant',['subject','tenant'],'tenant:other'),('other-memo',['resource','id'],'memo:other'),('changed-version',['context','memo_version'],2),('changed-approval',['context','approval_id'],'other'),('changed-digest',['context','approval_binding_digest'],'sha256:'+'0'*64),('consume',['action'],'consume')]: + for name,path,value in [('wrong-group',['subject','attributes','groups'],['net-kingdom-users']),('no-group',['subject','attributes','groups'],[]),('service',['subject','type'],'service'),('stale-mfa',['subject','attributes','assurance','at'],int(time.time())-901),('future-mfa',['subject','attributes','assurance','at'],int(time.time())+300),('no-mfa',['subject','attributes','assurance','mfa'],False),('forged-human-route',['subject','attributes','principal_type_source'],'registration-supplied'),('wrong-tenant',['subject','tenant'],'tenant:other'),('other-memo',['resource','id'],'memo:other'),('changed-version',['context','memo_version'],record['memo_version']+1),('changed-approval',['context','approval_id'],'other'),('changed-digest',['context','approval_binding_digest'],'sha256:'+'0'*64),('consume',['action'],'consume')]: candidate=copy.deepcopy(request); target=candidate for key in path[:-1]:target=target[key] target[path[-1]]=value diff --git a/workplans/FLEX-WP-0032-informed-decision-list-action.md b/workplans/FLEX-WP-0032-informed-decision-list-action.md index cf918a8..fc0a4d0 100644 --- a/workplans/FLEX-WP-0032-informed-decision-list-action.md +++ b/workplans/FLEX-WP-0032-informed-decision-list-action.md @@ -4,7 +4,7 @@ type: workplan title: "Admit a list action for the informed-decision overview without handing the scope to the consumer" domain: infotech repo: flex-auth -status: proposed +status: active flavor: implementation owner: claude topic_slug: netkingdom @@ -83,18 +83,21 @@ surface was admitted by the operator (`FLEX-WP-0027-T01`, `FLEX-WP-0028`). ```task id: FLEX-WP-0032-T01 -status: wait +status: done priority: high state_hub_task_id: "f741d47e-50b9-5eb1-81d9-ffec847be77a" ``` Owner: operator decides; `flex-auth` records as a `FLEX-DEC`. +2026-09-21: done. Operator chose **(B) exact-record** and a **12-hour** MFA +window for `list`. Recorded as `FLEX-DEC-2026-017`. + ## 2. Compile compact-sitting v3 ```task id: FLEX-WP-0032-T02 -status: todo +status: done priority: high state_hub_task_id: "a24fc5cf-f663-5338-97da-169af7fb47fb" ``` @@ -110,11 +113,17 @@ Owner: `flex-auth`. - A version bump, per `FLEX-DEC-2026-008`: a widened bar must be visible to the consumer as a version change. +2026-09-21: done. v3, digest +`sha256:dd40c80c5719851737178097cdee65afac108b54e19c07370e549b860f1a9655`. +The v2 act rule is kept unchanged so its effect cannot drift; `list` is a +separate `else` branch. T03 pins in `examples/informed-decision-sitting/list_only_records.json`, +copied from the T03 package's records. + ## 3. Fixtures and the exercise receipt ```task id: FLEX-WP-0032-T03 -status: todo +status: done priority: high state_hub_task_id: "984f11f4-6ec9-5f7d-840b-4dee2e121212" ``` @@ -130,6 +139,15 @@ sitting checks and T03's 57. Gate: `flex-auth validate`, `test-policy`, and the exercise scripts green; a receipt in `docs/evidence/`. +2026-09-21: done. 417 checks (168 v2 unchanged, 231 `list`, 18 no-act-widening), +receipt `docs/evidence/2026-09-21-sitting-review-policy-v3.json`; validate and +three Rego tests green; T03's 57 pass. + +Found on the way: `tools/exercise_t03_review_policy.py` had been failing since +`f85479c` moved the T03 records to memo version 2 — it still sent version 1, so +the reproduce command `FLEX-WP-0027-T01` cites was broken. Fixed to read each +record's own version. Test-only; no policy change. + ## 4. Publish and hand back ```task