From 125e018b8fa13b38a0cc66dfa9c724c040d84ae1 Mon Sep 17 00:00:00 2001 From: Abiorh001 Date: Mon, 20 Jul 2026 11:16:03 +0100 Subject: [PATCH 1/4] feat(auth): transfer ART activation custody --- .agent-loop/LOOP_STATE.md | 20 +- .agent-loop/REVIEW_LOG.md | 31 ++ .agent-loop/WORK_QUEUE.md | 2 +- .../ACTIVATION_CUSTODY.md | 14 +- .../CHUNK_MAP.md | 4 +- .../STATUS.md | 18 +- ...ART-CUSTODY-activation-custody-transfer.md | 85 ++++- ...REV-CUSTODY-activation-custody-transfer.md | 2 +- .../WS-AUTH-001-ART-CUSTODY.json | 9 + .../app/modules/authorization/catalogue.py | 97 ++--- backend/tests/test_authorization.py | 351 ++++++++++++++++-- docs/operations_authorization_service.md | 14 +- docs/spec_authorization_service.md | 27 +- 13 files changed, 554 insertions(+), 120 deletions(-) create mode 100644 .agent-loop/merge-intents/WS-AUTH-001-ART-CUSTODY.json diff --git a/.agent-loop/LOOP_STATE.md b/.agent-loop/LOOP_STATE.md index 90cb62344..3a2c9a4cc 100644 --- a/.agent-loop/LOOP_STATE.md +++ b/.agent-loop/LOOP_STATE.md @@ -36,14 +36,14 @@ - PR #122 merged the first automated post-merge memory implementation as `fc89fb6`; its schema-v1 cross-initiative next pointer is superseded by the schema-v2 initiative-local clean cut. -- PR-gate chunk: `WS-AUTH-001-09E`, explicitly started by the - user on 2026-07-19 from trusted `main` at `8d5eb15b` after contributor - foundation PR #153 and signed memory `66ab58d`. Its refreshed contract passed - all nine required L1 preimplementation tracks after resolving context, - feature-boundary, transaction, verification, coverage, docs, and reuse - findings. Runtime implementation, focused evidence, and all nine internal - reviewer tracks pass after repair; hosted Backend CI and human review are the - current gates. No feature action or call site becomes active in this chunk. +- PR #157 merged `WS-AUTH-001-09E` as `42a89b2d`; signed schema-v2 memory + `a5b9bad3` recorded completion and stopped at `WS-AUTH-001-ART-CUSTODY`. + The user explicitly started ART custody on 2026-07-20. Its repaired contract + passed all nine L1 preimplementation tracks and permits only the exact + availability-neutral 25-row typed owner transfer. Exact code `abb3fb1a` + passes all nine implementation tracks after proof repair; hosted checks and + human review remain. No feature action, call site, database row, or migration + changes in this chunk. - Scope checkpoint: AWS S3 is the only v0.1 production provider; MinIO is local/CI S3 protocol proof; LocalStorage is focused development/test; R2 and Flow Node are deferred. Product modules receive narrow artifact capabilities, @@ -65,8 +65,8 @@ put-attempt state, and migration `0028_artifact_admission`. - Authorization checkpoint: AUTH-07B through AUTH-09D-B merged through PRs #130, #131, #132, #143, #146, #148, and #152. Contributor foundation PR #153 - merged as `8d5eb15b`; AUTH-09E is now the sole active AUTH implementation - chunk. + merged as `8d5eb15b`; AUTH-09E merged through PR #157 as `42a89b2d`. + ART custody is now the sole active AUTH implementation chunk. - Parallel coverage work: `WS-QUAL-001-01B2` remains paused. Its last official whole-app result is `6466/8159` statements (`79.249908%`); no replacement evidence exists. diff --git a/.agent-loop/REVIEW_LOG.md b/.agent-loop/REVIEW_LOG.md index 0bcada82e..ce87fd1de 100644 --- a/.agent-loop/REVIEW_LOG.md +++ b/.agent-loop/REVIEW_LOG.md @@ -1,5 +1,36 @@ # Review Log +## 2026-07-20 - WS-AUTH-001-ART-CUSTODY Internal Review Passed + +- Exact code SHA `abb3fb1a035f544f5ee07b7d725451dfa2d90864` passes senior + engineering, QA/test, security/auth, product/ops, architecture, CI integrity, + docs, reuse/dedup, and test-delta review against trusted main `42a89b2d`. +- Initial candidate `e7c2602e` had self-referential owner expectations and + permissive documentation proof. The repair freezes literal owner truth, + parses exact custody tables and operations invariants, and proves no planned + ART action reaches revalidation or administrative grant dependencies. +- Forty-five focused cases, Ruff, stale scans, Markdown links, loop state, + merge intent, Alembic `0029`, migration no-diff, and diff integrity pass. + Hosted Backend remains the authoritative full-suite coverage gate. + +## 2026-07-20 - WS-AUTH-001-ART-CUSTODY Preimplementation Review Passed + +- PR #157 merged AUTH-09E to trusted `main` as `42a89b2d`; signed schema-v2 + memory `a5b9bad3` stopped and named ART custody. The user explicitly started + this chunk on 2026-07-20. +- Initial QA/security/product/CI/test-delta review rejected self-derived + baselines, ambiguous database-owner parity, incomplete all-action denial + proof, unclear `OPERATOR` wording, missing non-ART freeze and hosted CI gate, + and insufficient reuse/test-preservation constraints before runtime edits. +- The repaired contract freezes all 65 action mappings and availability values, + exact counts and service matrix, the 25-row/eight-custodian ART map, every + non-ART owner, Alembic head `0029`, and zero migration delta. It requires all + 25 actions to remain unavailable through the real kernel and keeps ART, REV, + and PREP as separate human-started chunks. +- Senior engineering, QA/test, security/auth, product/ops, architecture, CI + integrity, docs, reuse/dedup, and test-delta tracks pass. Implementation may + begin for ART custody only; no action availability or ART behavior may change. + ## 2026-07-20 - WS-AUTH-001-09E External Review Repair CodeRabbit raised two valid findings. The specification now says the service diff --git a/.agent-loop/WORK_QUEUE.md b/.agent-loop/WORK_QUEUE.md index e46c11373..9bd62f86c 100644 --- a/.agent-loop/WORK_QUEUE.md +++ b/.agent-loop/WORK_QUEUE.md @@ -4,7 +4,7 @@ | Chunk | Title | Risk | Status | |---|---|---:|---| -| `WS-AUTH-001-09E` | Fixed Service Runtime Admission | L1 | Runtime, focused evidence, and all nine internal tracks pass after repair; hosted Backend CI and human review remain | +| `WS-AUTH-001-ART-CUSTODY` | ART Activation Custody Transfer | L1 | Exact code `abb3fb1a` passed all nine internal tracks; hosted checks and human review remain | Live post-merge state remains read from signed `automation/loop-memory` output. This authored queue records the separately approved parallel chunks. diff --git a/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/ACTIVATION_CUSTODY.md b/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/ACTIVATION_CUSTODY.md index 14aefd313..ea98607eb 100644 --- a/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/ACTIVATION_CUSTODY.md +++ b/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/ACTIVATION_CUSTODY.md @@ -37,10 +37,16 @@ mappings, and availability must remain identical. | `WS-AUTH-001-ART-06A` | `artifact.post_submit.checker_input.materialize` | | `WS-AUTH-001-ART-06B` | `artifact.checker_output.write`, `artifact.checker_output.binding.create` | -`WS-AUTH-001-ART-CUSTODY` performs the atomic 25-row transfer to eight exact AUTH -groups and removes the seven historical ART owner enum values. It adds no migration because owner and -availability are typed metadata, while PostgreSQL preserves the exact -ActionId-to-PermissionId set. +`WS-AUTH-001-ART-CUSTODY` atomically transfers these 25 rows with exact owner +cardinalities `3/8/3/6/1/1/1/2` in the table order above and removes the seven +historical ART owner enum values. The `OPERATOR` suffix denotes only future +activation custody; it grants no Operator entitlement. All 25 actions remain +planned, including independently gated `artifact.verification_job.retry`, which +cannot be activated by read/status proof. The transfer adds no migration because +owner and availability are typed metadata, while PostgreSQL preserves the exact +ActionId-to-PermissionId set. The catalogue remains at 74 PermissionIds, +65 ActionIds, 17 active actions, and 48 planned actions; the seven-identity, +eleven-membership service matrix is unchanged. ## REV custody transfer diff --git a/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/CHUNK_MAP.md b/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/CHUNK_MAP.md index 14b0950d6..afa515700 100644 --- a/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/CHUNK_MAP.md +++ b/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/CHUNK_MAP.md @@ -36,8 +36,8 @@ stopped. | `WS-AUTH-001-09D-A` | Profile Lifecycle And Evidence Repair | L1 | Merged through PR #148 as `99ae4c9`; signed memory `cf8a3e8` passed | | `WS-AUTH-001-09D-B` | Identity-Link Lifecycle And Race Closure | L1 | Merged through PR #152 as `93dd392`; signed memory `912a6254` passed | | `WS-AUTH-001-CONTRIBUTOR-FOUNDATION` | Contributor Fields And Canonical-Human Lineage | L1 | Merged through PR #153 as `8d5eb15b`; signed memory `66ab58d` passed and stopped | -| `WS-AUTH-001-09E` | Fixed Service Runtime Admission | L1 | Runtime, focused evidence, and all nine internal tracks pass after repair; hosted Backend CI and human review remain | -| `WS-AUTH-001-ART-CUSTODY` | ART Activation Custody Transfer | L1 | Inactive until 09E merge/memory and explicit start | +| `WS-AUTH-001-09E` | Fixed Service Runtime Admission | L1 | Merged through PR #157 as `42a89b2d`; signed memory `a5b9bad3` passed | +| `WS-AUTH-001-ART-CUSTODY` | ART Activation Custody Transfer | L1 | Exact code `abb3fb1a` passed all nine internal tracks; hosted checks and human review remain | | `WS-AUTH-001-REV-CUSTODY` | REV Activation Custody Transfer | L1 | Inactive until 09E merge/memory and explicit start | | `WS-AUTH-001-PREP` | Prepared Mutation Authorization Protocol | L1 | Inactive until 09E merge/memory and explicit start | | `WS-AUTH-001-10` | Project Qualification And Contributor Role Grants | L1 | Proposed | diff --git a/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/STATUS.md b/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/STATUS.md index 529c9593b..3ff1bb457 100644 --- a/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/STATUS.md +++ b/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/STATUS.md @@ -115,14 +115,18 @@ None. `WS-AUTH-001-XINT` merged through PR #140. ## Active implementation chunk -`WS-AUTH-001-09E` - Fixed Service Runtime Admission. Explicitly started from -trusted `main` at `8d5eb15b`; the refreshed contract passed all nine required -L1 preimplementation tracks. Runtime implementation is active and changes no -feature action availability. +`WS-AUTH-001-ART-CUSTODY` - ART Activation Custody Transfer. PR #157 merged +AUTH-09E to trusted `main` as `42a89b2d`; signed schema-v2 memory `a5b9bad3` +recorded completion and stopped at ART custody. The user explicitly started +this chunk on 2026-07-20. Its repaired contract passed all nine required L1 +preimplementation tracks. Implementation changes only the 25 typed ART owner +values and keeps every feature action planned. Exact code SHA `abb3fb1a` passes +all nine internal implementation tracks after proof repair; PR publication and +hosted checks remain. ## Current review branch -`codex/ws-auth-001-09e-fixed-service-runtime-admission` +`codex/ws-auth-001-art-custody` ## Chunk status @@ -153,8 +157,8 @@ feature action availability. | `WS-AUTH-001-09D-A` | Merged | `codex/ws-auth-001-09d-actor-identity-lifecycle` | #148 | Merged as `99ae4c9`; signed memory `cf8a3e8` passed and stopped. | | `WS-AUTH-001-09D-B` | Merged | `codex/ws-auth-001-09d-b-identity-link-lifecycle` | #152 | Merged as `93dd392`; signed memory `912a6254` passed and stopped. | | `WS-AUTH-001-CONTRIBUTOR-FOUNDATION` | Merged | `codex/ws-auth-001-contributor-foundation` | #153 | Merged as `8d5eb15b`; signed memory `66ab58d` passed and stopped. | -| `WS-AUTH-001-09E` | PR gate | `codex/ws-auth-001-09e-fixed-service-runtime-admission` | - | Runtime, focused evidence, and all nine internal tracks pass after repair; hosted Backend CI and human review remain. | -| `WS-AUTH-001-ART-CUSTODY` | Proposed | - | - | Availability-neutral 25-row ART owner transfer after 09E. | +| `WS-AUTH-001-09E` | Merged | `codex/ws-auth-001-09e-fixed-service-runtime-admission` | #157 | Merged as `42a89b2d`; signed memory `a5b9bad3` passed and stopped. | +| `WS-AUTH-001-ART-CUSTODY` | PR gate | `codex/ws-auth-001-art-custody` | - | Exact code `abb3fb1a` passed all nine internal tracks after proof repair; hosted checks and human review remain. | | `WS-AUTH-001-REV-CUSTODY` | Proposed | - | - | Availability-neutral 19-row REV owner transfer after 09E. | | `WS-AUTH-001-PREP` | Proposed | - | - | AUTH-first prepared mutation protocol after 09E. | | `WS-AUTH-001-10` | Proposed | - | - | Project contributor grants. | diff --git a/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/chunks/WS-AUTH-001-ART-CUSTODY-activation-custody-transfer.md b/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/chunks/WS-AUTH-001-ART-CUSTODY-activation-custody-transfer.md index fd5347bcd..de5afdcf0 100644 --- a/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/chunks/WS-AUTH-001-ART-CUSTODY-activation-custody-transfer.md +++ b/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/chunks/WS-AUTH-001-ART-CUSTODY-activation-custody-transfer.md @@ -53,13 +53,49 @@ partial transfer or retained ART activation-owner enum ## Acceptance criteria - Exactly the 25 canonical rows move to the eight AUTH owner values. +- The exact owner cardinalities are `8/3/3/6/1/1/1/2` for + `WS-AUTH-001-ART-02D-OPERATOR`, `WS-AUTH-001-ART-02D-INTERNAL`, + `WS-AUTH-001-ART-03`, `WS-AUTH-001-ART-04A`, + `WS-AUTH-001-ART-04B`, `WS-AUTH-001-ART-05`, + `WS-AUTH-001-ART-06A`, and `WS-AUTH-001-ART-06B`, respectively. - All seven ART owner enum values are removed atomically. -- Catalogue ActionId, PermissionId, active/planned counts, static matrix rows, - and every ActionId-to-PermissionId pair remain exactly equal to the trusted - entry head; this chunk has a zero-count and zero-availability delta. -- Typed, PostgreSQL, audit, definition-owner, and documentation parity reject - missing, extra, dual, or changed mappings. -- Every ART action remains unavailable through the real kernel. +- Frozen expectations independent of the modified catalogue bind the entry + baseline to trusted `main` SHA `42a89b2deac8fc7672556a567a6124f8a4e5d423`: + all 65 `(ActionId, PermissionId, availability)` tuples, 74 PermissionIds, + 65 ActionIds, 17 active and 48 planned actions, and the exact seven-identity, + eleven-membership fixed-service matrix remain unchanged. This chunk has a + zero-count and zero-availability delta. +- The exact 25-row owner map is frozen independently of + `ACTION_DEFINITIONS`. Tests assert the eight new AUTH ART owners are present, + all seven historical ART owners are absent, and the catalogue rejects a + missing row, extra or duplicate row, wrong custodian, retained historical or + dual custody, changed mapping, and changed availability. +- Every non-ART owner assignment remains exactly equal to the frozen trusted + baseline, including all 19 REV rows and all seven historical REV owner enum + values. +- `WS-AUTH-001-ART-02D-OPERATOR` is only a future AUTH activation-custody + grouping. It grants no Operator authority and changes no permission, grant, + evaluator, route, service identity, or availability. In particular, + `artifact.verification_job.retry` remains planned and requires its own later + evaluator, guards, and independent activation proof; read/status proof cannot + activate retry. +- `ActionOwner` changes only in the typed catalogue. PostgreSQL and historical + audit evidence have no owner field and receive no write or rewrite. Database + and audit proof preserves the existing ActionId-to-PermissionId and evidence + contracts; it does not invent persisted owner parity. +- Canonical documentation tables enumerate the same 25-row/eight-owner handoff + and exact counts; documentation parity is checked deterministically in + addition to the stale-wording scan. +- Every one of the 25 ART actions remains unavailable through + `AuthorizationService.require()` using the real kernel. Each denial is + `action_unavailable`, is sensitive, records the exact action and permission, + and reaches no grant, evaluator, or ART behavior path. +- Alembic remains at the immutable entry head + `0029_shared_transactional_outbox`; `backend/alembic/**` has no diff and no + migration is added, edited, or allocated. +- This chunk transfers ART custody only. `WS-AUTH-001-REV-CUSTODY` remains a + separate later human-started chunk, followed by separately started + `WS-AUTH-001-PREP`; a combined ART/REV transfer is forbidden. ## Verification commands @@ -68,9 +104,40 @@ partial transfer or retained ART activation-owner enum (cd backend && WORKSTREAM_DATABASE_URL= .venv/bin/python -m pytest -q tests/test_authorization.py tests/test_auth.py --cov=app.modules.authorization --cov-report=term-missing --cov-fail-under=90) python3 scripts/check_stale_authorization_docs.py python3 scripts/check_markdown_links.py +test -z "$(git diff --name-only 42a89b2deac8fc7672556a567a6124f8a4e5d423 -- backend/alembic)" +(cd backend && test "$(.venv/bin/alembic heads | tr -d '[:space:]')" = "0029_shared_transactional_outbox(head)") git diff --check ``` +After push, the existing GitHub `Backend` workflow is the authoritative full +suite gate. It must pass its isolated backend suite, preserve repository-wide +coverage at or above 78 percent, preserve authorization-subsystem coverage at +or above 90 percent, and pass every existing workflow gate. The full suite runs +in GitHub Actions rather than on the user's slow local machine. This chunk does +not change workflows, scripts, exclusions, thresholds, or package commands. + +## Implementation and test reuse constraints + +- Extend the existing exact catalogue expectation and `_index_actions()` + fail-closed tests in `backend/tests/test_authorization.py`; do not add a + parallel catalogue validator or a second 65-row fixture. +- Add one hand-authored test-only 25-row ART custody fixture, independent of + `ACTION_DEFINITIONS`, `ACTION_BY_ID`, enum-name prefixes, and production + grouping logic. Reuse that one fixture for owner cardinality, mutation, + real-kernel denial, and documentation-parity proof. +- Reuse the existing `_runtime_context()`, `_runtime_service()`, and decision + evidence test abstractions for all 25 real-kernel denial cases; do not add a + duplicate fake authorization stack. +- Add no production owner-family helper, prefix classifier, compatibility + alias, or new registry abstraction for this metadata-only transfer. +- Documentation parity may consume the independent test fixture, but neither + production metadata nor rendered documentation may derive the other's + expected values. +- Existing tests may not be removed, weakened, skipped, xfailed, deselected, + or have assertions relaxed. Every modified existing expectation retains all + trusted-baseline assertions and changes only the exact 25 ART owner values. + Tests removed, skipped, or xfailed by this chunk must remain zero. + ## Required reviewers Senior engineering, QA/test, security/auth, product/ops, architecture, @@ -78,8 +145,10 @@ CI integrity, docs, reuse/dedup, and test delta. ## Human review focus -Verify exact 25-row/eight-owner custody transfer, unchanged mappings/counts, and zero -activation. +Verify the exact 25-row/eight-custodian ART transfer; all non-ART owners, +especially the 19 REV rows, remain unchanged; `OPERATOR` means a future custody +group rather than runtime entitlement; all 25 ART actions remain planned and +unavailable; and ART -> REV -> PREP remains separate and human-gated. ## Stop conditions diff --git a/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/chunks/WS-AUTH-001-REV-CUSTODY-activation-custody-transfer.md b/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/chunks/WS-AUTH-001-REV-CUSTODY-activation-custody-transfer.md index d9c4db9fd..4ed462a98 100644 --- a/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/chunks/WS-AUTH-001-REV-CUSTODY-activation-custody-transfer.md +++ b/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/chunks/WS-AUTH-001-REV-CUSTODY-activation-custody-transfer.md @@ -1,4 +1,4 @@ -# Chunk Contract: WS-AUTH-001-REV-CUSTODY — REV Activation Custody Transfer +# Chunk Contract: WS-AUTH-001-REV-CUSTODY - REV Activation Custody Transfer ## Parent initiative diff --git a/.agent-loop/merge-intents/WS-AUTH-001-ART-CUSTODY.json b/.agent-loop/merge-intents/WS-AUTH-001-ART-CUSTODY.json new file mode 100644 index 000000000..56eacb178 --- /dev/null +++ b/.agent-loop/merge-intents/WS-AUTH-001-ART-CUSTODY.json @@ -0,0 +1,9 @@ +{ + "chunk_id": "WS-AUTH-001-ART-CUSTODY", + "chunk_title": "ART Activation Custody Transfer", + "initiative_id": "WS-AUTH-001", + "next_chunk_id": "WS-AUTH-001-REV-CUSTODY", + "next_chunk_title": "REV Activation Custody Transfer", + "next_requires_explicit_start": true, + "schema_version": 2 +} diff --git a/backend/app/modules/authorization/catalogue.py b/backend/app/modules/authorization/catalogue.py index 0b06fcd99..8442cf26c 100644 --- a/backend/app/modules/authorization/catalogue.py +++ b/backend/app/modules/authorization/catalogue.py @@ -181,13 +181,14 @@ class ActionOwner(StrEnum): REV_09A = "WS-REV-001-09A" REV_11 = "WS-REV-001-11" REV_12 = "WS-REV-001-12" - ART_02D = "WS-ART-001-02D" - ART_03 = "WS-ART-001-03" - ART_04A = "WS-ART-001-04A" - ART_04B = "WS-ART-001-04B" - ART_05 = "WS-ART-001-05" - ART_06A = "WS-ART-001-06A" - ART_06B = "WS-ART-001-06B" + AUTH_ART_02D_INTERNAL = "WS-AUTH-001-ART-02D-INTERNAL" + AUTH_ART_02D_OPERATOR = "WS-AUTH-001-ART-02D-OPERATOR" + AUTH_ART_03 = "WS-AUTH-001-ART-03" + AUTH_ART_04A = "WS-AUTH-001-ART-04A" + AUTH_ART_04B = "WS-AUTH-001-ART-04B" + AUTH_ART_05 = "WS-AUTH-001-ART-05" + AUTH_ART_06A = "WS-AUTH-001-ART-06A" + AUTH_ART_06B = "WS-AUTH-001-ART-06B" @unique @@ -400,119 +401,129 @@ def _active( ActionOwner.REV_12, ), _planned( - ActionId.ARTIFACT_BINDING_READ, PermissionId.ARTIFACT_BINDING_READ, ActionOwner.ART_02D + ActionId.ARTIFACT_BINDING_READ, + PermissionId.ARTIFACT_BINDING_READ, + ActionOwner.AUTH_ART_02D_OPERATOR, ), _planned( - ActionId.ARTIFACT_REPLICA_READ, PermissionId.ARTIFACT_REPLICA_READ, ActionOwner.ART_02D + ActionId.ARTIFACT_REPLICA_READ, + PermissionId.ARTIFACT_REPLICA_READ, + ActionOwner.AUTH_ART_02D_OPERATOR, ), _planned( - ActionId.ARTIFACT_RECEIPT_READ, PermissionId.ARTIFACT_RECEIPT_READ, ActionOwner.ART_02D + ActionId.ARTIFACT_RECEIPT_READ, + PermissionId.ARTIFACT_RECEIPT_READ, + ActionOwner.AUTH_ART_02D_OPERATOR, ), _planned( ActionId.ARTIFACT_VERIFICATION_JOB_READ, PermissionId.ARTIFACT_VERIFICATION_JOB_READ, - ActionOwner.ART_02D, + ActionOwner.AUTH_ART_02D_OPERATOR, ), _planned( ActionId.ARTIFACT_VERIFICATION_JOB_RETRY, PermissionId.ARTIFACT_VERIFICATION_JOB_RETRY, - ActionOwner.ART_02D, + ActionOwner.AUTH_ART_02D_OPERATOR, ), _planned( ActionId.ARTIFACT_RECOVERY_ATTEMPT_READ, PermissionId.ARTIFACT_RECOVERY_ATTEMPT_READ, - ActionOwner.ART_02D, + ActionOwner.AUTH_ART_02D_OPERATOR, + ), + _planned( + ActionId.ARTIFACT_AUDIT_READ, + PermissionId.ARTIFACT_AUDIT_READ, + ActionOwner.AUTH_ART_02D_OPERATOR, ), - _planned(ActionId.ARTIFACT_AUDIT_READ, PermissionId.ARTIFACT_AUDIT_READ, ActionOwner.ART_02D), _planned( ActionId.OPERATIONS_ARTIFACT_STORAGE_ADMISSION_READ, PermissionId.OPERATIONS_STATUS_READ, - ActionOwner.ART_02D, + ActionOwner.AUTH_ART_02D_OPERATOR, ), _planned( ActionId.ARTIFACT_GUIDE_SOURCE_INGEST, PermissionId.ARTIFACT_GUIDE_SOURCE_INGEST, - ActionOwner.ART_03, + ActionOwner.AUTH_ART_03, ), _planned( ActionId.ARTIFACT_GUIDE_SOURCE_READ, PermissionId.ARTIFACT_GUIDE_SOURCE_READ, - ActionOwner.ART_03, + ActionOwner.AUTH_ART_03, ), _planned( ActionId.ARTIFACT_UPLOAD_SESSION_CREATE, PermissionId.ARTIFACT_UPLOAD_SESSION_CREATE, - ActionOwner.ART_04A, + ActionOwner.AUTH_ART_04A, ), _planned( ActionId.ARTIFACT_UPLOAD_SESSION_READ, PermissionId.ARTIFACT_UPLOAD_SESSION_READ, - ActionOwner.ART_04A, + ActionOwner.AUTH_ART_04A, ), _planned( ActionId.ARTIFACT_UPLOAD_ITEM_WRITE, PermissionId.ARTIFACT_UPLOAD_ITEM_WRITE, - ActionOwner.ART_04A, + ActionOwner.AUTH_ART_04A, ), _planned( ActionId.ARTIFACT_UPLOAD_SESSION_SEAL, PermissionId.ARTIFACT_UPLOAD_SESSION_SEAL, - ActionOwner.ART_04A, + ActionOwner.AUTH_ART_04A, ), _planned( ActionId.ARTIFACT_UPLOAD_SESSION_CANCEL, PermissionId.ARTIFACT_UPLOAD_SESSION_CANCEL, - ActionOwner.ART_04A, + ActionOwner.AUTH_ART_04A, ), _planned( ActionId.ARTIFACT_UPLOAD_SESSION_EXPIRE, PermissionId.ARTIFACT_UPLOAD_SESSION_EXPIRE, - ActionOwner.ART_04A, + ActionOwner.AUTH_ART_04A, ), _planned( ActionId.ARTIFACT_GUIDE_SOURCE_BINDING_CREATE, PermissionId.ARTIFACT_BINDING_CREATE, - ActionOwner.ART_03, + ActionOwner.AUTH_ART_03, ), _planned( ActionId.ARTIFACT_SUBMISSION_BINDING_CREATE, PermissionId.ARTIFACT_BINDING_CREATE, - ActionOwner.ART_05, + ActionOwner.AUTH_ART_05, ), _planned( ActionId.ARTIFACT_CHECKER_OUTPUT_BINDING_CREATE, PermissionId.ARTIFACT_BINDING_CREATE, - ActionOwner.ART_06B, + ActionOwner.AUTH_ART_06B, ), _planned( ActionId.ARTIFACT_VERIFICATION_EXECUTE, PermissionId.ARTIFACT_VERIFICATION_EXECUTE, - ActionOwner.ART_02D, + ActionOwner.AUTH_ART_02D_INTERNAL, ), _planned( ActionId.ARTIFACT_PENDING_WORK_SCAN, PermissionId.ARTIFACT_PENDING_WORK_SCAN, - ActionOwner.ART_02D, + ActionOwner.AUTH_ART_02D_INTERNAL, ), _planned( ActionId.ARTIFACT_PUT_ATTEMPT_RESOLVE, PermissionId.ARTIFACT_PUT_ATTEMPT_RESOLVE, - ActionOwner.ART_02D, + ActionOwner.AUTH_ART_02D_INTERNAL, ), _planned( ActionId.ARTIFACT_PRE_SUBMIT_CHECKER_INPUT_MATERIALIZE, PermissionId.ARTIFACT_CHECKER_INPUT_MATERIALIZE, - ActionOwner.ART_04B, + ActionOwner.AUTH_ART_04B, ), _planned( ActionId.ARTIFACT_POST_SUBMIT_CHECKER_INPUT_MATERIALIZE, PermissionId.ARTIFACT_CHECKER_INPUT_MATERIALIZE, - ActionOwner.ART_06A, + ActionOwner.AUTH_ART_06A, ), _planned( ActionId.ARTIFACT_CHECKER_OUTPUT_WRITE, PermissionId.ARTIFACT_CHECKER_OUTPUT_WRITE, - ActionOwner.ART_06B, + ActionOwner.AUTH_ART_06B, ), ) @@ -669,47 +680,47 @@ def _index_service_actions( expected_metadata = { ActionId.ARTIFACT_VERIFICATION_EXECUTE: ( PermissionId.ARTIFACT_VERIFICATION_EXECUTE, - ActionOwner.ART_02D, + ActionOwner.AUTH_ART_02D_INTERNAL, ), ActionId.ARTIFACT_PUT_ATTEMPT_RESOLVE: ( PermissionId.ARTIFACT_PUT_ATTEMPT_RESOLVE, - ActionOwner.ART_02D, + ActionOwner.AUTH_ART_02D_INTERNAL, ), ActionId.ARTIFACT_PENDING_WORK_SCAN: ( PermissionId.ARTIFACT_PENDING_WORK_SCAN, - ActionOwner.ART_02D, + ActionOwner.AUTH_ART_02D_INTERNAL, ), ActionId.ARTIFACT_UPLOAD_SESSION_EXPIRE: ( PermissionId.ARTIFACT_UPLOAD_SESSION_EXPIRE, - ActionOwner.ART_04A, + ActionOwner.AUTH_ART_04A, ), ActionId.ARTIFACT_GUIDE_SOURCE_BINDING_CREATE: ( PermissionId.ARTIFACT_BINDING_CREATE, - ActionOwner.ART_03, + ActionOwner.AUTH_ART_03, ), ActionId.ARTIFACT_SUBMISSION_BINDING_CREATE: ( PermissionId.ARTIFACT_BINDING_CREATE, - ActionOwner.ART_05, + ActionOwner.AUTH_ART_05, ), ActionId.ARTIFACT_CHECKER_OUTPUT_BINDING_CREATE: ( PermissionId.ARTIFACT_BINDING_CREATE, - ActionOwner.ART_06B, + ActionOwner.AUTH_ART_06B, ), ActionId.ARTIFACT_GUIDE_SOURCE_READ: ( PermissionId.ARTIFACT_GUIDE_SOURCE_READ, - ActionOwner.ART_03, + ActionOwner.AUTH_ART_03, ), ActionId.ARTIFACT_PRE_SUBMIT_CHECKER_INPUT_MATERIALIZE: ( PermissionId.ARTIFACT_CHECKER_INPUT_MATERIALIZE, - ActionOwner.ART_04B, + ActionOwner.AUTH_ART_04B, ), ActionId.ARTIFACT_POST_SUBMIT_CHECKER_INPUT_MATERIALIZE: ( PermissionId.ARTIFACT_CHECKER_INPUT_MATERIALIZE, - ActionOwner.ART_06A, + ActionOwner.AUTH_ART_06A, ), ActionId.ARTIFACT_CHECKER_OUTPUT_WRITE: ( PermissionId.ARTIFACT_CHECKER_OUTPUT_WRITE, - ActionOwner.ART_06B, + ActionOwner.AUTH_ART_06B, ), } if set(rows) != SERVICE_IDENTITIES: diff --git a/backend/tests/test_authorization.py b/backend/tests/test_authorization.py index 1839fa4ec..e61e2b9dd 100644 --- a/backend/tests/test_authorization.py +++ b/backend/tests/test_authorization.py @@ -138,6 +138,134 @@ DIGEST = "sha256:" + "a" * 64 +ART_CUSTODY_EXPECTATIONS = { + "artifact.binding.read": ( + "artifact.binding.read", + "WS-AUTH-001-ART-02D-OPERATOR", + "planned", + ), + "artifact.replica.read": ( + "artifact.replica.read", + "WS-AUTH-001-ART-02D-OPERATOR", + "planned", + ), + "artifact.receipt.read": ( + "artifact.receipt.read", + "WS-AUTH-001-ART-02D-OPERATOR", + "planned", + ), + "artifact.verification_job.read": ( + "artifact.verification_job.read", + "WS-AUTH-001-ART-02D-OPERATOR", + "planned", + ), + "artifact.verification_job.retry": ( + "artifact.verification_job.retry", + "WS-AUTH-001-ART-02D-OPERATOR", + "planned", + ), + "artifact.recovery_attempt.read": ( + "artifact.recovery_attempt.read", + "WS-AUTH-001-ART-02D-OPERATOR", + "planned", + ), + "artifact.audit.read": ( + "artifact.audit.read", + "WS-AUTH-001-ART-02D-OPERATOR", + "planned", + ), + "operations.artifact_storage_admission.read": ( + "operations.status.read", + "WS-AUTH-001-ART-02D-OPERATOR", + "planned", + ), + "artifact.verification.execute": ( + "artifact.verification.execute", + "WS-AUTH-001-ART-02D-INTERNAL", + "planned", + ), + "artifact.pending_work.scan": ( + "artifact.pending_work.scan", + "WS-AUTH-001-ART-02D-INTERNAL", + "planned", + ), + "artifact.put_attempt.resolve": ( + "artifact.put_attempt.resolve", + "WS-AUTH-001-ART-02D-INTERNAL", + "planned", + ), + "artifact.guide_source.ingest": ( + "artifact.guide_source.ingest", + "WS-AUTH-001-ART-03", + "planned", + ), + "artifact.guide_source.read": ( + "artifact.guide_source.read", + "WS-AUTH-001-ART-03", + "planned", + ), + "artifact.guide_source.binding.create": ( + "artifact.binding.create", + "WS-AUTH-001-ART-03", + "planned", + ), + "artifact.upload_session.create": ( + "artifact.upload_session.create", + "WS-AUTH-001-ART-04A", + "planned", + ), + "artifact.upload_session.read": ( + "artifact.upload_session.read", + "WS-AUTH-001-ART-04A", + "planned", + ), + "artifact.upload_item.write": ( + "artifact.upload_item.write", + "WS-AUTH-001-ART-04A", + "planned", + ), + "artifact.upload_session.seal": ( + "artifact.upload_session.seal", + "WS-AUTH-001-ART-04A", + "planned", + ), + "artifact.upload_session.cancel": ( + "artifact.upload_session.cancel", + "WS-AUTH-001-ART-04A", + "planned", + ), + "artifact.upload_session.expire": ( + "artifact.upload_session.expire", + "WS-AUTH-001-ART-04A", + "planned", + ), + "artifact.pre_submit.checker_input.materialize": ( + "artifact.checker_input.materialize", + "WS-AUTH-001-ART-04B", + "planned", + ), + "artifact.submission.binding.create": ( + "artifact.binding.create", + "WS-AUTH-001-ART-05", + "planned", + ), + "artifact.post_submit.checker_input.materialize": ( + "artifact.checker_input.materialize", + "WS-AUTH-001-ART-06A", + "planned", + ), + "artifact.checker_output.write": ( + "artifact.checker_output.write", + "WS-AUTH-001-ART-06B", + "planned", + ), + "artifact.checker_output.binding.create": ( + "artifact.binding.create", + "WS-AUTH-001-ART-06B", + "planned", + ), +} + def _admin_resource_context( request: AdminRoleGrantIssueRequest | AdminRoleGrantRevokeRequest, @@ -224,37 +352,10 @@ def test_closed_permission_and_action_catalogue_is_exact_and_non_executable() -> "WS-REV-001-12", ), "review.projection.rebuild": ("operations.projection.rebuild", "WS-REV-001-12"), - "artifact.binding.read": ("artifact.binding.read", "WS-ART-001-02D"), - "artifact.replica.read": ("artifact.replica.read", "WS-ART-001-02D"), - "artifact.receipt.read": ("artifact.receipt.read", "WS-ART-001-02D"), - "artifact.verification_job.read": ("artifact.verification_job.read", "WS-ART-001-02D"), - "artifact.verification_job.retry": ("artifact.verification_job.retry", "WS-ART-001-02D"), - "artifact.recovery_attempt.read": ("artifact.recovery_attempt.read", "WS-ART-001-02D"), - "artifact.audit.read": ("artifact.audit.read", "WS-ART-001-02D"), - "operations.artifact_storage_admission.read": ("operations.status.read", "WS-ART-001-02D"), - "artifact.guide_source.ingest": ("artifact.guide_source.ingest", "WS-ART-001-03"), - "artifact.guide_source.read": ("artifact.guide_source.read", "WS-ART-001-03"), - "artifact.upload_session.create": ("artifact.upload_session.create", "WS-ART-001-04A"), - "artifact.upload_session.read": ("artifact.upload_session.read", "WS-ART-001-04A"), - "artifact.upload_item.write": ("artifact.upload_item.write", "WS-ART-001-04A"), - "artifact.upload_session.seal": ("artifact.upload_session.seal", "WS-ART-001-04A"), - "artifact.upload_session.cancel": ("artifact.upload_session.cancel", "WS-ART-001-04A"), - "artifact.upload_session.expire": ("artifact.upload_session.expire", "WS-ART-001-04A"), - "artifact.guide_source.binding.create": ("artifact.binding.create", "WS-ART-001-03"), - "artifact.submission.binding.create": ("artifact.binding.create", "WS-ART-001-05"), - "artifact.checker_output.binding.create": ("artifact.binding.create", "WS-ART-001-06B"), - "artifact.verification.execute": ("artifact.verification.execute", "WS-ART-001-02D"), - "artifact.pending_work.scan": ("artifact.pending_work.scan", "WS-ART-001-02D"), - "artifact.put_attempt.resolve": ("artifact.put_attempt.resolve", "WS-ART-001-02D"), - "artifact.pre_submit.checker_input.materialize": ( - "artifact.checker_input.materialize", - "WS-ART-001-04B", - ), - "artifact.post_submit.checker_input.materialize": ( - "artifact.checker_input.materialize", - "WS-ART-001-06A", - ), - "artifact.checker_output.write": ("artifact.checker_output.write", "WS-ART-001-06B"), + **{ + action: (permission, owner) + for action, (permission, owner, _availability) in ART_CUSTODY_EXPECTATIONS.items() + }, "authorization.permission_catalogue.read": ("admin_role.read", "WS-AUTH-001-08"), "authorization.admin_role_definitions.read": ("admin_role.read", "WS-AUTH-001-08"), "admin_role_grant.list": ("admin_role.read", "WS-AUTH-001-08"), @@ -310,6 +411,45 @@ def test_closed_permission_and_action_catalogue_is_exact_and_non_executable() -> ) for definition in ACTION_DEFINITIONS } == expected + assert { + action: ( + ACTION_BY_ID[ActionId(action)].permission_id.value, + ACTION_BY_ID[ActionId(action)].owner.value, + ACTION_BY_ID[ActionId(action)].availability.value, + ) + for action in ART_CUSTODY_EXPECTATIONS + } == ART_CUSTODY_EXPECTATIONS + assert { + owner: sum(definition.owner is owner for definition in ACTION_DEFINITIONS) + for owner in { + ActionOwner.AUTH_ART_02D_OPERATOR, + ActionOwner.AUTH_ART_02D_INTERNAL, + ActionOwner.AUTH_ART_03, + ActionOwner.AUTH_ART_04A, + ActionOwner.AUTH_ART_04B, + ActionOwner.AUTH_ART_05, + ActionOwner.AUTH_ART_06A, + ActionOwner.AUTH_ART_06B, + } + } == { + ActionOwner.AUTH_ART_02D_OPERATOR: 8, + ActionOwner.AUTH_ART_02D_INTERNAL: 3, + ActionOwner.AUTH_ART_03: 3, + ActionOwner.AUTH_ART_04A: 6, + ActionOwner.AUTH_ART_04B: 1, + ActionOwner.AUTH_ART_05: 1, + ActionOwner.AUTH_ART_06A: 1, + ActionOwner.AUTH_ART_06B: 2, + } + assert all(not owner.value.startswith("WS-ART-") for owner in ActionOwner) + assert sum( + definition.availability is ActionAvailability.ACTIVE + for definition in ACTION_DEFINITIONS + ) == 17 + assert sum( + definition.availability is ActionAvailability.PLANNED + for definition in ACTION_DEFINITIONS + ) == 48 assert resolve_executable_action(ActionId.ACTOR_PROFILE_READ_SELF).permission_id is ( PermissionId.ACTOR_PROFILE_READ_SELF ) @@ -354,6 +494,90 @@ def test_fixed_service_action_matrix_is_exact_planned_and_immutable() -> None: SERVICE_ACTIONS_BY_IDENTITY[ServiceIdentity.ARTIFACT_VERIFIER] = frozenset() # type: ignore[index] +def test_art_custody_documentation_matches_the_independent_catalogue_fixture() -> None: + repository_root = Path(__file__).resolve().parents[2] + custody_documents = ( + repository_root / "docs/spec_authorization_service.md", + repository_root + / ".agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service" + / "ACTIVATION_CUSTODY.md", + ) + expected_custody = { + action: owner + for action, (_permission, owner, _availability) in ART_CUSTODY_EXPECTATIONS.items() + } + expected_owner_counts = { + "WS-AUTH-001-ART-02D-OPERATOR": 8, + "WS-AUTH-001-ART-02D-INTERNAL": 3, + "WS-AUTH-001-ART-03": 3, + "WS-AUTH-001-ART-04A": 6, + "WS-AUTH-001-ART-04B": 1, + "WS-AUTH-001-ART-05": 1, + "WS-AUTH-001-ART-06A": 1, + "WS-AUTH-001-ART-06B": 2, + } + + for document in custody_documents: + rows = document.read_text(encoding="utf-8").splitlines() + header_index = next( + index + for index, row in enumerate(rows) + if row + in { + "| AUTH activation custodian | Exact planned ActionIds |", + "| AUTH activation chunk | Exact planned ActionIds |", + } + ) + table_rows: list[str] = [] + for row in rows[header_index + 2 :]: + if not row.startswith("|"): + break + table_rows.append(row) + parsed: dict[str, str] = {} + duplicates: set[str] = set() + for row in table_rows: + cells = [cell.strip() for cell in row.split("|")] + assert len(cells) == 4 + owner = cells[1].strip("`") + for action in cells[2].split("`")[1::2]: + if action in parsed: + duplicates.add(action) + parsed[action] = owner + assert duplicates == set() + assert parsed == expected_custody + assert { + owner: sum(parsed_owner == owner for parsed_owner in parsed.values()) + for owner in set(parsed.values()) + } == expected_owner_counts + + spec_rows = (repository_root / "docs/spec_authorization_service.md").read_text( + encoding="utf-8" + ).splitlines() + parsed_permissions: dict[str, str] = {} + for row in spec_rows: + cells = [cell.strip() for cell in row.split("|")] + if len(cells) < 6: + continue + action = cells[1].strip("`") + if action in ART_CUSTODY_EXPECTATIONS: + assert action not in parsed_permissions + parsed_permissions[action] = cells[2].strip("`") + assert parsed_permissions == { + action: permission + for action, (permission, _owner, _availability) in ART_CUSTODY_EXPECTATIONS.items() + } + + operations = (repository_root / "docs/operations_authorization_service.md").read_text( + encoding="utf-8" + ) + assert "all 25 ART rows to eight exact AUTH custodians" in operations + assert "The 19 REV rows retain their historical" in operations + assert "The ART transfer adds no migration" in operations + assert "does not grant Operator" in operations + assert "verification retry remains independently gated" in operations + assert "74 PermissionIds, 65 ActionIds, 17 active actions, and\n48 planned actions" in operations + + @pytest.mark.parametrize( "mutation", ["missing_identity", "extra_action", "duplicate_action", "swapped_rows"], @@ -389,7 +613,7 @@ def test_fixed_service_action_matrix_rejects_metadata_drift( if metadata == "permission": changed = replace(definition, permission_id=PermissionId.ARTIFACT_PENDING_WORK_SCAN) elif metadata == "owner": - changed = replace(definition, owner=ActionOwner.ART_03) + changed = replace(definition, owner=ActionOwner.AUTH_ART_03) else: changed = replace(definition, availability=ActionAvailability.ACTIVE) action_index = dict(ACTION_BY_ID) @@ -872,7 +1096,7 @@ async def record_conflict(self, **kwargs) -> None: ActionDefinition( ActionId.ARTIFACT_CHECKER_OUTPUT_WRITE, PermissionId.ARTIFACT_CHECKER_OUTPUT_WRITE, - ActionOwner.ART_02D, + ActionOwner.AUTH_ART_02D_OPERATOR, ActionAvailability.PLANNED, ), ), @@ -884,7 +1108,7 @@ async def record_conflict(self, **kwargs) -> None: ActionDefinition( ActionId.ARTIFACT_CHECKER_OUTPUT_WRITE, PermissionId.ARTIFACT_CHECKER_OUTPUT_WRITE, - ActionOwner.ART_06B, + ActionOwner.AUTH_ART_06B, ActionAvailability.ACTIVE, ), ), @@ -896,7 +1120,19 @@ async def record_conflict(self, **kwargs) -> None: ActionDefinition( ActionId.ARTIFACT_CHECKER_OUTPUT_WRITE, "unknown.permission", # type: ignore[arg-type] - ActionOwner.ART_06B, + ActionOwner.AUTH_ART_06B, + ActionAvailability.PLANNED, + ), + ), + "invalid row", + ), + ( + ACTION_DEFINITIONS[:-1] + + ( + ActionDefinition( + ActionId.ARTIFACT_CHECKER_OUTPUT_WRITE, + PermissionId.ARTIFACT_CHECKER_OUTPUT_WRITE, + "WS-ART-001-06B", # type: ignore[arg-type] ActionAvailability.PLANNED, ), ), @@ -908,7 +1144,7 @@ async def record_conflict(self, **kwargs) -> None: ActionDefinition( "unknown.action", # type: ignore[arg-type] PermissionId.ARTIFACT_CHECKER_OUTPUT_WRITE, - ActionOwner.ART_06B, + ActionOwner.AUTH_ART_06B, ActionAvailability.PLANNED, ), ), @@ -932,7 +1168,7 @@ async def record_conflict(self, **kwargs) -> None: ActionDefinition( ActionId.ARTIFACT_CHECKER_OUTPUT_WRITE, PermissionId.ARTIFACT_CHECKER_OUTPUT_WRITE, - ActionOwner.ART_06B, + ActionOwner.AUTH_ART_06B, "unknown.availability", # type: ignore[arg-type] ), ), @@ -3249,6 +3485,47 @@ async def test_authorization_kernel_denies_active_action_without_implemented_aut assert evidence.events[0].event_type is AuthorityEventType.SENSITIVE_AUTHORIZATION_DENIED +@pytest.mark.parametrize( + ("action_id", "expected_metadata"), + ART_CUSTODY_EXPECTATIONS.items(), +) +async def test_art_custody_actions_remain_unavailable_without_runtime_dispatch( + action_id: str, + expected_metadata: tuple[str, str, str], +) -> None: + expected_permission, _owner, expected_availability = expected_metadata + action = ActionId(action_id) + context = _runtime_context() + + async def unexpected_revalidation(*_args, **_kwargs): + raise AssertionError("planned ART custody action reached runtime revalidation") + + class UnexpectedAuthorizationDependency: + def __getattr__(self, name: str): + async def unexpected(*_args, **_kwargs): + raise AssertionError(f"planned ART custody action reached {name}") + + return unexpected + + service, evidence = _runtime_service(context, revalidate=unexpected_revalidation) + service._admin = UnexpectedAuthorizationDependency() # type: ignore[assignment] + resource = SystemResourceContext(resource_type="system", resource_id="workstream:system") + + with pytest.raises(AuthorizationDenied) as exc_info: + await service.require(action, resource) + + decision = exc_info.value.decision + assert decision.denial_code is AuthorizationDenialCode.ACTION_UNAVAILABLE + assert decision.action_id is action + assert decision.permission_id is PermissionId(expected_permission) + assert ACTION_BY_ID[action].availability.value == expected_availability + assert decision.revalidated is False + assert len(evidence.events) == 1 + assert evidence.events[0].event_type is AuthorityEventType.SENSITIVE_AUTHORIZATION_DENIED + assert evidence.events[0].action_id == action_id + assert evidence.events[0].permission_id == expected_permission + + async def test_unknown_action_denies_without_fabricated_evidence() -> None: context = _runtime_context() service, evidence = _runtime_service(context) diff --git a/docs/operations_authorization_service.md b/docs/operations_authorization_service.md index 0357e2ae7..7f9695ba1 100644 --- a/docs/operations_authorization_service.md +++ b/docs/operations_authorization_service.md @@ -614,9 +614,11 @@ actions, `actor.service.provision`, `actor.profile.read`, identity-link lifecycle actions are active; the other 48 entries remain planned and non-executable. The target post-custody invariant is that planned runtime entries contain only action, permission, exact -AUTH activation owner, and availability. Until the availability-neutral custody -transfers merge, the 25 ART and 19 REV rows retain their historical feature -owner values as an explicitly blocked exception. +AUTH activation owner, and availability. The availability-neutral ART custody +transfer assigns all 25 ART rows to eight exact AUTH custodians without changing +their mappings or planned availability. The 19 REV rows retain their historical +feature-owner values as an explicitly blocked exception until the separate REV +custody chunk receives its own human start and merges. Their owning feature must publish the approved principal/resource/guard/surface/ transaction contract before registration or activation, but those foreign facts do not become free-form catalogue fields. Startup validation failure is a release @@ -624,7 +626,11 @@ blocker, not a reason to relax catalogue checks. PR #139 requires availability-neutral transfer of all 25 ART and 19 REV owner rows to exact AUTH chunks before feature activation. Counts and mappings remain -unchanged. Catalogue totals are derived from the trusted entry head: four later +unchanged. The ART transfer adds no migration and does not grant Operator +authority; its `OPERATOR` suffix denotes only future activation custody, and +verification retry remains independently gated from read/status actions. +Catalogue totals remain 74 PermissionIds, 65 ActionIds, 17 active actions, and +48 planned actions. Four later REV registrations add exactly four planned and zero active actions, while the review-evidence binding registration adds exactly one planned and zero active action, in either order. Neither addition is operational until its complete diff --git a/docs/spec_authorization_service.md b/docs/spec_authorization_service.md index a715da7bd..8746f97d7 100644 --- a/docs/spec_authorization_service.md +++ b/docs/spec_authorization_service.md @@ -361,9 +361,12 @@ dynamically, or changes availability. The following table is the single source of truth for artifact ActionId-to- PermissionId mappings, principal/resource facts, and ART hidden-behavior -ownership. AUTH-07A registers only each row's stable `ActionId`, approved - `PermissionId`, historical pre-transfer owner value, and `planned` -availability. Its principal-class and canonical-resource columns are not AUTH +ownership. AUTH-07A registered each row's stable `ActionId`, approved +`PermissionId`, historical owner value, and `planned` availability. +`WS-AUTH-001-ART-CUSTODY` has now replaced only those historical owner values +with the exact AUTH activation custodians below; mappings, availability, and +ART hidden-behavior ownership are unchanged. Its principal-class and +canonical-resource columns are not AUTH registry fields and are not executable authority; the owning WS-ART chunk adopts them with its hidden canonical resource composer, guards, surface declaration, and behavior tests. The complete AUTH activation-custody transfer is separately @@ -371,6 +374,24 @@ canonical in `.agent-loop/initiatives/WS-XINT-001-lifecycle-boundary-reconciliation/AUTH_ART_HANDOFF.md`. A mapping is not a permission alias. +| AUTH activation custodian | Exact planned ActionIds | +|---|---| +| `WS-AUTH-001-ART-02D-INTERNAL` | `artifact.verification.execute`, `artifact.pending_work.scan`, `artifact.put_attempt.resolve` | +| `WS-AUTH-001-ART-02D-OPERATOR` | `artifact.binding.read`, `artifact.replica.read`, `artifact.receipt.read`, `artifact.verification_job.read`, `artifact.verification_job.retry`, `artifact.recovery_attempt.read`, `artifact.audit.read`, `operations.artifact_storage_admission.read` | +| `WS-AUTH-001-ART-03` | `artifact.guide_source.ingest`, `artifact.guide_source.read`, `artifact.guide_source.binding.create` | +| `WS-AUTH-001-ART-04A` | `artifact.upload_session.create`, `artifact.upload_session.read`, `artifact.upload_item.write`, `artifact.upload_session.seal`, `artifact.upload_session.cancel`, `artifact.upload_session.expire` | +| `WS-AUTH-001-ART-04B` | `artifact.pre_submit.checker_input.materialize` | +| `WS-AUTH-001-ART-05` | `artifact.submission.binding.create` | +| `WS-AUTH-001-ART-06A` | `artifact.post_submit.checker_input.materialize` | +| `WS-AUTH-001-ART-06B` | `artifact.checker_output.write`, `artifact.checker_output.binding.create` | + +The `OPERATOR` suffix names future activation custody only; it creates no +Operator grant or entitlement. All 25 actions remain planned and unavailable. +`artifact.verification_job.retry` requires its own later evaluator, guards, and +independent activation proof; read/status proof cannot activate retry. The +transfer adds no migration, and all 19 REV rows retain their historical owners +until the separately started REV custody chunk. + | ActionId | PermissionId | Principal class | Canonical resource | Resource-owning WS-ART chunk | |---|---|---|---|---| | `artifact.binding.read` | `artifact.binding.read` | Operator | artifact binding | `02D` | From f19c5611ef74ce0cc83cb9a834b624b3844087ae Mon Sep 17 00:00:00 2001 From: Abiorh001 Date: Mon, 20 Jul 2026 11:35:25 +0100 Subject: [PATCH 2/4] docs(agent-loop): bind ART custody review evidence --- ...01-ART-CUSTODY-internal-review-evidence.md | 71 +++++++++++++++++++ ...WS-AUTH-001-ART-CUSTODY-pr-trust-bundle.md | 64 +++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 .agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/reviews/WS-AUTH-001-ART-CUSTODY-internal-review-evidence.md create mode 100644 .agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/reviews/WS-AUTH-001-ART-CUSTODY-pr-trust-bundle.md diff --git a/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/reviews/WS-AUTH-001-ART-CUSTODY-internal-review-evidence.md b/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/reviews/WS-AUTH-001-ART-CUSTODY-internal-review-evidence.md new file mode 100644 index 000000000..366cd2d09 --- /dev/null +++ b/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/reviews/WS-AUTH-001-ART-CUSTODY-internal-review-evidence.md @@ -0,0 +1,71 @@ +# WS-AUTH-001-ART-CUSTODY Internal Review Evidence + +Reviewed code SHA: `125e018b8fa13b38a0cc66dfa9c724c040d84ae1` + +Reviewed implementation SHA: `abb3fb1a035f544f5ee07b7d725451dfa2d90864` + +Reviewed against trusted main: `42a89b2deac8fc7672556a567a6124f8a4e5d423` + +Reviewed at: `2026-07-20T10:28:21Z` + +Reviewer run IDs: `plan_product`, `plan_qa`, `plan_security` + +Reviewer tracks: senior engineering, QA/test, security/auth, product/ops, +architecture, CI integrity, docs, reuse/dedup, and test delta + +## Deterministic Evidence + +- Ruff passed for the complete backend application and test trees. +- Forty-five focused catalogue, fixed-service matrix, fail-closed construction, + documentation-parity, and real-kernel custody cases passed. The 25 ART + actions each deny as sensitive `action_unavailable` evidence with exact + action and permission and cannot reach revalidation or administrative grant + dependencies. +- The literal test fixture independently freezes all 25 action, permission, + owner, and `planned` values. Exact documentation parsing rejects missing, + extra, duplicate, or wrong-custodian rows and checks owner cardinalities, + spec mappings, counts, and operations invariants. +- Stale Workstream and authorization wording scans, Markdown links, loop-memory + state, merge-intent validation, Alembic `0029_shared_transactional_outbox` + head, migration-directory no-diff, and diff integrity pass. +- No workflow, dependency, ActionId, PermissionId, mapping, availability, + evaluator, grant, route, service identity, matrix membership, persistence, + audit schema, or migration changed. +- The unchanged GitHub Backend workflow remains the mandatory hosted full-suite + proof for the 78 percent repository-wide and 90 percent authorization + subsystem coverage floors. No local full-suite result is claimed. + +## Reviewer Results + +| Reviewer | Result | Blocking findings | Notes | +|---|---|---|---| +| senior engineering | PASS AFTER FIXES | none | Exact bounded documentation parsing replaced permissive substring proof. | +| QA/test | PASS AFTER FIXES | none | Literal fixtures, exact docs parity, and exploding downstream dependencies close self-derived proof gaps. | +| security/auth | PASS | none | All 25 actions stay planned and unavailable; no database, audit, grant, or runtime path changes. | +| product/ops | PASS | none | `OPERATOR` is custody-only, retry stays independent, and ART -> REV sequencing remains human-gated. | +| architecture | PASS | none | AUTH changes activation custody metadata while ART retains feature facts, guards, and behavior. | +| CI integrity | PASS | none | No CI weakening; hosted full coverage remains mandatory. | +| docs | PASS | none | Spec, operations, custody, state, queue, map, and contract wording are consistent. | +| reuse/dedup | PASS | none | Existing catalogue/kernel helpers are reused; the sole literal fixture and parser remain test-only. | +| test delta | PASS | none | No test removal, skip, xfail, deselection, assertion relaxation, or threshold change. | + +## Findings Resolved + +Valid findings addressed: yes + +Open sub-agent sessions: none + +Initial candidate `e7c2602e` used production enum members as expected owner +truth and only checked documentation substring presence. Repaired exact code +SHA `abb3fb1a` uses literal action/permission/owner/availability truth, parses +the bounded canonical tables exactly, asserts operations invariants, and fails +if any planned ART action reaches a downstream authorization dependency. All +nine implementation tracks pass with no remaining finding. Final candidate +`125e018b` adds only deterministic status/review-log updates; all nine tracks +confirmed that exact SHA without a remaining finding. + +## Remaining Risk And Gate + +GitHub Backend, Agent Gates, external review, and explicit human review remain. +All 25 ART actions remain planned and unavailable. REV custody remains a +separate successor requiring signed memory and an explicit human start. diff --git a/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/reviews/WS-AUTH-001-ART-CUSTODY-pr-trust-bundle.md b/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/reviews/WS-AUTH-001-ART-CUSTODY-pr-trust-bundle.md new file mode 100644 index 000000000..0e7f52a60 --- /dev/null +++ b/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/reviews/WS-AUTH-001-ART-CUSTODY-pr-trust-bundle.md @@ -0,0 +1,64 @@ +# WS-AUTH-001-ART-CUSTODY PR Trust Bundle + +## Goal + +Transfer exactly 25 planned ART action-owner labels to eight exact AUTH +activation custodians without changing permission mappings, availability, or +ART behavior. + +## Changes And Design + +- Removes seven historical ART `ActionOwner` enum values and adds eight exact + AUTH activation-custodian values. +- Changes only the owner field of the 25 canonical ART definitions and the + matching closed fixed-service metadata expectations. +- Preserves 74 PermissionIds, 65 ActionIds, 17 active and 48 planned actions, + every ActionId-to-PermissionId pair, all non-ART owners, and the exact + seven-identity/eleven-membership service matrix. +- Adds literal independent catalogue truth, exact documentation parity, and + all-25 real-kernel denial proof. + +## Scope Control + +No migration, database or audit rewrite, availability change, evaluator, +resource composer, route, command, grant, service provisioning, identity, +matrix membership, or ART runtime behavior is included. `OPERATOR` denotes +future activation custody only and creates no entitlement. Verification retry +remains planned and independently gated. + +## Proof And CI Integrity + +- Ruff passed for `app` and `tests`. +- 45 focused catalogue/kernel/documentation tests passed. +- Stale wording, stale authorization docs, Markdown links, loop-memory state, + merge intent, Alembic-head/no-migration, and diff checks passed. +- No tests or assertions were removed or weakened; no skips, xfails, + deselection, exclusions, workflows, scripts, or thresholds changed. +- GitHub Backend remains the authoritative full-suite gate for global coverage + at or above 78 percent and authorization coverage at or above 90 percent. + +## Internal Review + +Final reviewed SHA `125e018b8fa13b38a0cc66dfa9c724c040d84ae1`, containing +reviewed implementation `abb3fb1a035f544f5ee07b7d725451dfa2d90864`, against +trusted main `42a89b2deac8fc7672556a567a6124f8a4e5d423` passes senior engineering, +QA/test, security/auth, product/ops, architecture, CI integrity, docs, +reuse/dedup, and test-delta review after all valid proof findings were repaired. + +## Remaining Risk And Follow-up + +Hosted Backend CI, Agent Gates, CodeRabbit, and human review remain. The merge +intent names only `WS-AUTH-001-REV-CUSTODY`, which remains inactive until this +PR merges, signed memory succeeds, and the user explicitly starts it. + +## Human Review Focus + +Verify the exact 25-row/eight-custodian owner-only delta, unchanged non-ART and +REV owners, unchanged mappings/counts/matrix/availability, custody-only +`OPERATOR` meaning, independent retry gating, and absence of a migration. + +## Human Merge Ownership + +The agent may publish and repair this branch but may not merge it. Only the +human may approve this PR for merge. Trusted-main automation owns post-merge +schema-v2 memory generation when the workflow succeeds. From a20ab6b2004e2f7a13e1e0d600595f0af7d67985 Mon Sep 17 00:00:00 2001 From: Abiorh001 Date: Mon, 20 Jul 2026 11:44:12 +0100 Subject: [PATCH 3/4] fix(agent-gates): preserve authored trusted-main status --- .agent-loop/LOOP_STATE.md | 20 +++++++++---------- .agent-loop/WORK_QUEUE.md | 2 +- .../CHUNK_MAP.md | 4 ++-- .../STATUS.md | 18 +++++++---------- 4 files changed, 20 insertions(+), 24 deletions(-) diff --git a/.agent-loop/LOOP_STATE.md b/.agent-loop/LOOP_STATE.md index 3a2c9a4cc..90cb62344 100644 --- a/.agent-loop/LOOP_STATE.md +++ b/.agent-loop/LOOP_STATE.md @@ -36,14 +36,14 @@ - PR #122 merged the first automated post-merge memory implementation as `fc89fb6`; its schema-v1 cross-initiative next pointer is superseded by the schema-v2 initiative-local clean cut. -- PR #157 merged `WS-AUTH-001-09E` as `42a89b2d`; signed schema-v2 memory - `a5b9bad3` recorded completion and stopped at `WS-AUTH-001-ART-CUSTODY`. - The user explicitly started ART custody on 2026-07-20. Its repaired contract - passed all nine L1 preimplementation tracks and permits only the exact - availability-neutral 25-row typed owner transfer. Exact code `abb3fb1a` - passes all nine implementation tracks after proof repair; hosted checks and - human review remain. No feature action, call site, database row, or migration - changes in this chunk. +- PR-gate chunk: `WS-AUTH-001-09E`, explicitly started by the + user on 2026-07-19 from trusted `main` at `8d5eb15b` after contributor + foundation PR #153 and signed memory `66ab58d`. Its refreshed contract passed + all nine required L1 preimplementation tracks after resolving context, + feature-boundary, transaction, verification, coverage, docs, and reuse + findings. Runtime implementation, focused evidence, and all nine internal + reviewer tracks pass after repair; hosted Backend CI and human review are the + current gates. No feature action or call site becomes active in this chunk. - Scope checkpoint: AWS S3 is the only v0.1 production provider; MinIO is local/CI S3 protocol proof; LocalStorage is focused development/test; R2 and Flow Node are deferred. Product modules receive narrow artifact capabilities, @@ -65,8 +65,8 @@ put-attempt state, and migration `0028_artifact_admission`. - Authorization checkpoint: AUTH-07B through AUTH-09D-B merged through PRs #130, #131, #132, #143, #146, #148, and #152. Contributor foundation PR #153 - merged as `8d5eb15b`; AUTH-09E merged through PR #157 as `42a89b2d`. - ART custody is now the sole active AUTH implementation chunk. + merged as `8d5eb15b`; AUTH-09E is now the sole active AUTH implementation + chunk. - Parallel coverage work: `WS-QUAL-001-01B2` remains paused. Its last official whole-app result is `6466/8159` statements (`79.249908%`); no replacement evidence exists. diff --git a/.agent-loop/WORK_QUEUE.md b/.agent-loop/WORK_QUEUE.md index 9bd62f86c..e46c11373 100644 --- a/.agent-loop/WORK_QUEUE.md +++ b/.agent-loop/WORK_QUEUE.md @@ -4,7 +4,7 @@ | Chunk | Title | Risk | Status | |---|---|---:|---| -| `WS-AUTH-001-ART-CUSTODY` | ART Activation Custody Transfer | L1 | Exact code `abb3fb1a` passed all nine internal tracks; hosted checks and human review remain | +| `WS-AUTH-001-09E` | Fixed Service Runtime Admission | L1 | Runtime, focused evidence, and all nine internal tracks pass after repair; hosted Backend CI and human review remain | Live post-merge state remains read from signed `automation/loop-memory` output. This authored queue records the separately approved parallel chunks. diff --git a/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/CHUNK_MAP.md b/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/CHUNK_MAP.md index afa515700..14b0950d6 100644 --- a/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/CHUNK_MAP.md +++ b/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/CHUNK_MAP.md @@ -36,8 +36,8 @@ stopped. | `WS-AUTH-001-09D-A` | Profile Lifecycle And Evidence Repair | L1 | Merged through PR #148 as `99ae4c9`; signed memory `cf8a3e8` passed | | `WS-AUTH-001-09D-B` | Identity-Link Lifecycle And Race Closure | L1 | Merged through PR #152 as `93dd392`; signed memory `912a6254` passed | | `WS-AUTH-001-CONTRIBUTOR-FOUNDATION` | Contributor Fields And Canonical-Human Lineage | L1 | Merged through PR #153 as `8d5eb15b`; signed memory `66ab58d` passed and stopped | -| `WS-AUTH-001-09E` | Fixed Service Runtime Admission | L1 | Merged through PR #157 as `42a89b2d`; signed memory `a5b9bad3` passed | -| `WS-AUTH-001-ART-CUSTODY` | ART Activation Custody Transfer | L1 | Exact code `abb3fb1a` passed all nine internal tracks; hosted checks and human review remain | +| `WS-AUTH-001-09E` | Fixed Service Runtime Admission | L1 | Runtime, focused evidence, and all nine internal tracks pass after repair; hosted Backend CI and human review remain | +| `WS-AUTH-001-ART-CUSTODY` | ART Activation Custody Transfer | L1 | Inactive until 09E merge/memory and explicit start | | `WS-AUTH-001-REV-CUSTODY` | REV Activation Custody Transfer | L1 | Inactive until 09E merge/memory and explicit start | | `WS-AUTH-001-PREP` | Prepared Mutation Authorization Protocol | L1 | Inactive until 09E merge/memory and explicit start | | `WS-AUTH-001-10` | Project Qualification And Contributor Role Grants | L1 | Proposed | diff --git a/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/STATUS.md b/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/STATUS.md index 3ff1bb457..529c9593b 100644 --- a/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/STATUS.md +++ b/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/STATUS.md @@ -115,18 +115,14 @@ None. `WS-AUTH-001-XINT` merged through PR #140. ## Active implementation chunk -`WS-AUTH-001-ART-CUSTODY` - ART Activation Custody Transfer. PR #157 merged -AUTH-09E to trusted `main` as `42a89b2d`; signed schema-v2 memory `a5b9bad3` -recorded completion and stopped at ART custody. The user explicitly started -this chunk on 2026-07-20. Its repaired contract passed all nine required L1 -preimplementation tracks. Implementation changes only the 25 typed ART owner -values and keeps every feature action planned. Exact code SHA `abb3fb1a` passes -all nine internal implementation tracks after proof repair; PR publication and -hosted checks remain. +`WS-AUTH-001-09E` - Fixed Service Runtime Admission. Explicitly started from +trusted `main` at `8d5eb15b`; the refreshed contract passed all nine required +L1 preimplementation tracks. Runtime implementation is active and changes no +feature action availability. ## Current review branch -`codex/ws-auth-001-art-custody` +`codex/ws-auth-001-09e-fixed-service-runtime-admission` ## Chunk status @@ -157,8 +153,8 @@ hosted checks remain. | `WS-AUTH-001-09D-A` | Merged | `codex/ws-auth-001-09d-actor-identity-lifecycle` | #148 | Merged as `99ae4c9`; signed memory `cf8a3e8` passed and stopped. | | `WS-AUTH-001-09D-B` | Merged | `codex/ws-auth-001-09d-b-identity-link-lifecycle` | #152 | Merged as `93dd392`; signed memory `912a6254` passed and stopped. | | `WS-AUTH-001-CONTRIBUTOR-FOUNDATION` | Merged | `codex/ws-auth-001-contributor-foundation` | #153 | Merged as `8d5eb15b`; signed memory `66ab58d` passed and stopped. | -| `WS-AUTH-001-09E` | Merged | `codex/ws-auth-001-09e-fixed-service-runtime-admission` | #157 | Merged as `42a89b2d`; signed memory `a5b9bad3` passed and stopped. | -| `WS-AUTH-001-ART-CUSTODY` | PR gate | `codex/ws-auth-001-art-custody` | - | Exact code `abb3fb1a` passed all nine internal tracks after proof repair; hosted checks and human review remain. | +| `WS-AUTH-001-09E` | PR gate | `codex/ws-auth-001-09e-fixed-service-runtime-admission` | - | Runtime, focused evidence, and all nine internal tracks pass after repair; hosted Backend CI and human review remain. | +| `WS-AUTH-001-ART-CUSTODY` | Proposed | - | - | Availability-neutral 25-row ART owner transfer after 09E. | | `WS-AUTH-001-REV-CUSTODY` | Proposed | - | - | Availability-neutral 19-row REV owner transfer after 09E. | | `WS-AUTH-001-PREP` | Proposed | - | - | AUTH-first prepared mutation protocol after 09E. | | `WS-AUTH-001-10` | Proposed | - | - | Project contributor grants. | From 2cbce2d5e9413659ea837ea95c10f1e86d2eae9f Mon Sep 17 00:00:00 2001 From: Abiorh001 Date: Mon, 20 Jul 2026 11:48:47 +0100 Subject: [PATCH 4/4] docs(agent-loop): bind ART custody CI repair --- ...-AUTH-001-ART-CUSTODY-internal-review-evidence.md | 12 +++++++++--- .../WS-AUTH-001-ART-CUSTODY-pr-trust-bundle.md | 5 ++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/reviews/WS-AUTH-001-ART-CUSTODY-internal-review-evidence.md b/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/reviews/WS-AUTH-001-ART-CUSTODY-internal-review-evidence.md index 366cd2d09..06513517f 100644 --- a/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/reviews/WS-AUTH-001-ART-CUSTODY-internal-review-evidence.md +++ b/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/reviews/WS-AUTH-001-ART-CUSTODY-internal-review-evidence.md @@ -1,12 +1,14 @@ # WS-AUTH-001-ART-CUSTODY Internal Review Evidence -Reviewed code SHA: `125e018b8fa13b38a0cc66dfa9c724c040d84ae1` +Reviewed code SHA: `a20ab6b2004e2f7a13e1e0d600595f0af7d67985` Reviewed implementation SHA: `abb3fb1a035f544f5ee07b7d725451dfa2d90864` +Reviewed pre-CI status SHA: `125e018b8fa13b38a0cc66dfa9c724c040d84ae1` + Reviewed against trusted main: `42a89b2deac8fc7672556a567a6124f8a4e5d423` -Reviewed at: `2026-07-20T10:28:21Z` +Reviewed at: `2026-07-20T10:49:58Z` Reviewer run IDs: `plan_product`, `plan_qa`, `plan_security` @@ -62,7 +64,11 @@ the bounded canonical tables exactly, asserts operations invariants, and fails if any planned ART action reaches a downstream authorization dependency. All nine implementation tracks pass with no remaining finding. Final candidate `125e018b` adds only deterministic status/review-log updates; all nine tracks -confirmed that exact SHA without a remaining finding. +confirmed that exact SHA without a remaining finding. GitHub Agent Gates then +exposed a trusted-main fixture invariant for four authored status files. Repair +`a20ab6b2` restores those files byte-for-byte to `origin/main` without changing +the gate or implementation; all 88 agent-gate regression tests and all nine +exact-SHA repair tracks pass. ## Remaining Risk And Gate diff --git a/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/reviews/WS-AUTH-001-ART-CUSTODY-pr-trust-bundle.md b/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/reviews/WS-AUTH-001-ART-CUSTODY-pr-trust-bundle.md index 0e7f52a60..096dc47d5 100644 --- a/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/reviews/WS-AUTH-001-ART-CUSTODY-pr-trust-bundle.md +++ b/.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/reviews/WS-AUTH-001-ART-CUSTODY-pr-trust-bundle.md @@ -39,11 +39,14 @@ remains planned and independently gated. ## Internal Review -Final reviewed SHA `125e018b8fa13b38a0cc66dfa9c724c040d84ae1`, containing +Final reviewed SHA `a20ab6b2004e2f7a13e1e0d600595f0af7d67985`, containing reviewed implementation `abb3fb1a035f544f5ee07b7d725451dfa2d90864`, against trusted main `42a89b2deac8fc7672556a567a6124f8a4e5d423` passes senior engineering, QA/test, security/auth, product/ops, architecture, CI integrity, docs, reuse/dedup, and test-delta review after all valid proof findings were repaired. +The final CI repair preserves four authored trusted-main status fixtures +byte-for-byte rather than weakening their gate; all 88 agent-gate regression +tests pass. Canonical live state remains automation-owned. ## Remaining Risk And Follow-up