Skip to content

WS-XINT-003-02B: activate guide-bound policy mutations - #248

Merged
abiorh-claw merged 10 commits into
mainfrom
codex/ws-xint-003-02b-policy-mutation-activation
Aug 3, 2026
Merged

WS-XINT-003-02B: activate guide-bound policy mutations#248
abiorh-claw merged 10 commits into
mainfrom
codex/ws-xint-003-02b-policy-mutation-activation

Conversation

@Abiorh001

@Abiorh001 Abiorh001 commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

PR Trust Bundle: WS-XINT-003-02B

Chunk

WS-XINT-003-02B — Guide-bound policy mutation activation.

Goal and human-approved intent

Activate exactly project.review_policy.update and
project.revision_policy.update so a covered Project Manager can append and
select immutable policy versions for one exact draft guide. Do not activate the
review or revision lifecycle.

What changed and why

  • Added the two guide-bound PUT routes and one policy mutation service.
  • Added append-only ReviewPolicy/RevisionPolicy provenance and one replay ledger.
  • Extended the existing opaque PREP protocol with exact policy lineage facts.
  • Added deferred PostgreSQL custody joining the selected successor, real
    predecessor, replay record, authority evidence, actor/link/grant, and digest.
  • Replaced remaining live fixture bypasses with the public policy routes and
    retained explicitly historical incomplete fixtures only where required.

This removes direct or embedded policy writes and makes the authorized path the
sole live configuration boundary.

Design and alternatives rejected

The design uses opaque exact If-Match selectors, UUID idempotency keys,
replay classification before PREP, locked selector revalidation, single-use
transaction-bound PREP consumption, append-only rows, and atomic evidence.
Raw AuthorizationContext authority, role-only fallback, mutable policy rows,
digest-only selectors, and a second authorization protocol were rejected.

Scope and product behavior

Only draft-guide policy configuration changes. Reviewer queues, leases,
findings, decisions, contributor revisions, artifacts, payments, contribution
records, and reputation remain unavailable or unchanged.

Acceptance proof and tests

  • Focused policy/PREP tests: 11 passed.
  • New-subsystem coverage: 10 passed, 90.58 percent.
  • Artifact architecture: 20 passed.
  • Ruff, migration SQL generation, stale authorization/artifact/wording scans,
    Markdown links, and git diff --check: passed.
  • Full PostgreSQL-isolated and repository coverage gates are delegated to
    GitHub Actions as required; no local full-suite run was performed.

Test delta and CI integrity

No tests were removed, skipped, or weakened. Live project/task/E2E fixtures now
use the real routes. Historical artifact fixtures remain explicitly
legacy_incomplete. No workflow, lane, threshold, or failure behavior changed.

Reviewer results

Architecture, security, product/operations, docs, and CI integrity passed. QA,
senior engineering, reuse/dedup, and test-delta passed with low non-blocking
risks. Every blocking first-round finding was fixed and re-reviewed.

External review

GitHub Backend / test, Agent Gates / agent-gates, and CodeRabbit must pass
on the exact final head. Valid findings must be corrected before human merge.

Remaining risks and follow-up

The API may later expose the opaque replacement selector as a response ETag.
The next REV/AUTH lifecycle chunk remains separate and requires a new explicit
start after this PR is human-merged.

Human review focus

Confirm replay-before-PREP ordering, exact successor/predecessor custody,
Project Manager scope, append-only behavior, denial side-effect ordering, and
the absence of review/revision lifecycle activation.

Human merge ownership

Only the human may merge this PR.

Summary by CodeRabbit

  • New Features

    • Added guide-specific endpoints for updating review and revision policies.
    • Enabled authorized Project Managers to attach or replace policies while guides are in draft.
    • Added idempotent updates with optimistic concurrency checks, replay handling, and immutable policy history.
    • Policy updates now support independent configuration of review and revision policies.
  • Documentation

    • Documented authorization requirements, endpoint usage, concurrency controls, and policy lifecycle behavior.
  • Bug Fixes

    • Improved validation for revision resubmission settings and stale or conflicting policy updates.
    • Added safeguards for policy provenance, authorization evidence, and replay consistency.

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c3bbff23-750c-46dc-813b-3f0d180833f5

📥 Commits

Reviewing files that changed from the base of the PR and between 1a92f2a and 8ee91a5.

📒 Files selected for processing (6)
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/REVIEW_LOG.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/reviews/WS-XINT-003-02B-external-review-response.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/reviews/WS-XINT-003-02B-pr-trust-bundle.md
  • backend/app/modules/projects/policy_mutation_service.py
  • backend/tests/test_alembic.py
  • backend/tests/test_project_policy_mutations.py
🚧 Files skipped from review as they are similar to previous changes (4)
  • backend/tests/test_project_policy_mutations.py
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/reviews/WS-XINT-003-02B-pr-trust-bundle.md
  • backend/app/modules/projects/policy_mutation_service.py
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/REVIEW_LOG.md

📝 Walkthrough

Walkthrough

The change activates guide-bound review-policy and revision-policy PUT routes. It adds authorization binding, immutable provenance, idempotency replay custody, migration enforcement, repository persistence, API tests, documentation, and initiative review records.

Changes

Guide-bound policy mutation activation

Layer / File(s) Summary
Mutation contracts and authorization binding
.agent-loop/initiatives/..., backend/app/modules/authorization/*, docs/spec_authorization_service.md
The two policy actions are active. PREP authorization validates project, guide, request, digest, generation, predecessor, and draft-status facts.
Policy lineage and replay custody
backend/alembic/versions/0048_review_revision_policy_authority.py, backend/app/modules/projects/models.py, backend/app/modules/projects/policy_mutation_replay_repository.py, backend/app/modules/projects/repository.py
Migration and models add provenance, immutable lineage, independent selectors, deferred custody checks, and idempotency records. Repositories append policy versions and complete replay records.
Mutation orchestration and API wiring
backend/app/modules/projects/policy_mutation_service.py, backend/app/modules/projects/policy_mutation_router.py, backend/app/api/router.py
The service validates If-Match, replay state, guide state, and authorization. The API exposes versioned guide-bound review-policy and revision-policy PUT routes.
Validation and operational records
backend/tests/*, backend/scripts/*, docs/*, .agent-loop/initiatives/...
Tests and contract checks cover authorization, replay, ETags, custody, transactions, migration behavior, and HTTP-based policy setup. Documentation and review records describe the implemented scope and validation evidence.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant PolicyMutationRouter
  participant ProjectPolicyMutationService
  participant PreparedAuthorizationService
  participant PolicyMutationReplayRepository
  participant ProjectRepository

  Client->>PolicyMutationRouter: PUT guide-bound policy with Idempotency-Key and If-Match
  PolicyMutationRouter->>ProjectPolicyMutationService: replace policy
  ProjectPolicyMutationService->>PolicyMutationReplayRepository: reserve or classify replay
  ProjectPolicyMutationService->>PreparedAuthorizationService: prepare and consume authorization
  ProjectPolicyMutationService->>ProjectRepository: append immutable policy version
  ProjectPolicyMutationService->>PolicyMutationReplayRepository: complete committed replay
  PolicyMutationRouter-->>Client: policy response or structured conflict
Loading

Possibly related PRs

Suggested reviewers: abiorh-claw

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 41.54% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies activation of guide-bound policy mutations, which is the main change in the pull request.
Description check ✅ Passed The description covers the goal, design, scope, behavior, evidence, tests, review status, risks, follow-up, and human review focus.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/ws-xint-003-02b-policy-mutation-activation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Abiorh001
Abiorh001 force-pushed the codex/ws-xint-003-02b-policy-mutation-activation branch from d6e136d to f19540c Compare August 2, 2026 17:43

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (10)
backend/app/modules/projects/policy_mutation_router.py (2)

51-59: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Document why key is a parameter that is immediately deleted.

policy_authorization_actor declares key only to force FastAPI to resolve require_policy_mutation_key before actor resolution and rate-control consumption. del key then discards it. A future reader can remove the parameter as dead code. That change would allow an invalid Idempotency-Key to consume rate-control budget and resolve an actor before the 422 is raised.

Add a one-line comment stating the ordering intent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/app/modules/projects/policy_mutation_router.py` around lines 51 - 59,
Document the ordering intent in policy_authorization_actor with a one-line
comment immediately before del key: retain key solely to force
require_policy_mutation_key to run before actor resolution and rate-control
consumption, then discard the validated value.

110-113: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Type the authorization dependency tuple.

Both routes annotate the dependency as a bare tuple and then unpack it into three names. A type checker cannot verify the arity or the element types of the unpack against what policy_authorization returns.

Annotate it as tuple[UUID, ResolvedActor, PreparedAuthorizationService] in both routes, and add the matching return annotation to policy_authorization.

Also applies to: 134-137

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/app/modules/projects/policy_mutation_router.py` around lines 110 -
113, Update both route handlers’ authorization dependency annotations to
tuple[UUID, ResolvedActor, PreparedAuthorizationService], and add the same tuple
return annotation to policy_authorization. Preserve the existing three-value
unpacking and ensure the required UUID, ResolvedActor, and
PreparedAuthorizationService symbols are imported or reused from their existing
definitions.
backend/tests/test_project_policy_mutations.py (2)

622-622: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the exact exception type.

pytest.raises(Exception, match="only draft guides") passes for any exception whose message contains that substring. The service raises GuideEditBlocked, which is importable from app.modules.projects.service. This file already imports ProjectNotFound from that module (Line 40).

💚 Proposed fix to tighten the assertion
-    with pytest.raises(Exception, match="only draft guides"):
+    with pytest.raises(GuideEditBlocked, match="only draft guides"):

Update the import at Line 40:

from app.modules.projects.service import GuideEditBlocked, ProjectNotFound
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/tests/test_project_policy_mutations.py` at line 622, Update the
test’s service import to include GuideEditBlocked, then change the pytest.raises
assertion around the draft-guide mutation to expect GuideEditBlocked instead of
the broad Exception type while preserving the existing message match.

113-118: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

_Replay.reserve always returns claimed, leaving three service branches uncovered.

The fake always returns "claimed". _replace in policy_mutation_service.py branches on the reserve disposition at Lines 295-300 and handles three other outcomes: mismatch raises idempotency_mismatch, pending raises idempotency_pending, and replayed returns the stored response. No test drives _replace through any of them.

test_policy_service_denies_stale_guide_and_replay_mismatch reaches idempotency_mismatch through the _existing fast path, not through reserve. test_replay_repository_owns_claim_classification_and_completion verifies the repository classification in isolation, not the service reaction to it.

Add a parameterized disposition to the fake so the three branches are exercised.

As per coding guidelines: "New or materially changed backend subsystems must maintain at least 90% test coverage".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/tests/test_project_policy_mutations.py` around lines 113 - 118,
Update the test fake’s _Replay.reserve method to return a configurable
disposition and corresponding record, then parameterize the relevant policy
mutation service tests to exercise mismatch, pending, and replayed outcomes
through _replace. Assert each branch’s expected service behavior while
preserving the existing claimed behavior and repository classification coverage.

Source: Coding guidelines

backend/app/modules/projects/policy_mutation_service.py (1)

153-153: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Annotate _existing.

_existing declares seven parameters and a return value with no type annotations. Every other method on ProjectPolicyMutationService is annotated. response_type in particular is a Pydantic model class used for model_validate, and the untyped signature hides that contract.

Add annotations consistent with _replace.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/app/modules/projects/policy_mutation_service.py` at line 153,
Annotate the `_existing` method signature with parameter and return types,
matching the established annotations used by `_replace`. Explicitly type
`response_type` as the Pydantic model class contract required by
`model_validate`, and annotate all remaining parameters and the async return
value consistently with the service’s existing conventions.
backend/scripts/api_contract_e2e.py (1)

647-654: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Document the arguments of configure_policy_boundaries.

The docstring is a single summary line. request_json and create_policy_bundle_for_guide in this same file document every argument in an Args: section. guide_version is the least obvious parameter here, because it is used only for the direct PaymentPolicy insert and not for the two HTTP calls.

Add an Args: section.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/scripts/api_contract_e2e.py` around lines 647 - 654, Expand the
docstring for configure_policy_boundaries with an Args: section documenting
client, token, project_id, guide_id, and guide_version, explicitly noting that
guide_version is used for the direct PaymentPolicy insert. Keep the existing
summary line and match the argument-documentation style used by request_json and
create_policy_bundle_for_guide.
backend/tests/test_alembic.py (1)

11884-11901: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the selector constraint expression, not only its presence.

The test asserts selector_constraint: True for both the upgraded and the downgraded state. policy_selection_shape exists in both states, so this assertion passes regardless of the migration's actual change. The behavioral change is the relaxation from "both policy selections set or both null" to "each selection independently set or null" (migration Lines 86-100, inverted at Lines 391-402).

That relaxation is a precondition for the two independent PUT routes, because the first route call leaves one selection populated and the other null. The round-trip test does not currently prove it.

Compare pg_get_constraintdef for policy_selection_shape across the two states, or assert the partial-selection write succeeds after upgrade and fails after downgrade.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/tests/test_alembic.py` around lines 11884 - 11901, The test’s
selector_constraint assertions only verify presence, not the migration’s changed
constraint behavior. Update the assertions around the upgraded and downgraded
shape checks to compare the actual policy_selection_shape expression via
pg_get_constraintdef, or add equivalent partial-selection writes that succeed
after upgrade and fail after downgrade, while preserving the existing state
checks.
backend/app/modules/projects/policy_mutation_replay_repository.py (2)

22-31: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add docstrings to the public repository methods.

find, reserve, and complete have no docstrings. Every public method in the sibling ProjectRepository in backend/app/modules/projects/repository.py carries one. reserve in particular returns an untyped disposition string with four possible values (claimed, mismatch, pending, replayed), and the meaning of each is only discoverable by reading the caller.

Document the return contract of reserve at minimum.

Also applies to: 94-111

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/app/modules/projects/policy_mutation_replay_repository.py` around
lines 22 - 31, Add docstrings to the public methods find, reserve, and complete
in the policy mutation replay repository, matching the documentation style used
by ProjectRepository. Document each method’s purpose and return behavior,
including reserve’s four possible disposition values: claimed, mismatch,
pending, and replayed.

33-92: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider a typed disposition instead of bare strings.

reserve returns tuple[str, PolicyMutationIdempotencyRecord]. The caller in policy_mutation_service.py (Lines 295-300) branches on the literal values "claimed", "mismatch", and "pending", and treats every other value as replayed. A typo in either module produces a silent behavior change with no type error.

Use Literal["claimed", "mismatch", "pending", "replayed"] as the return annotation, or a small enum.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/app/modules/projects/policy_mutation_replay_repository.py` around
lines 33 - 92, Update PolicyMutationReplayRepository.reserve to use a typed
disposition—prefer Literal["claimed", "mismatch", "pending", "replayed"] or a
small enum—instead of str, and update the policy mutation service branching to
consume that type while preserving the existing four outcomes.
backend/alembic/versions/0048_review_revision_policy_authority.py (1)

103-155: 🚀 Performance & Scalability | 🔵 Trivial

Consider an index for the ledger lookup by policy_id.

The deferred custody trigger queries policy_mutation_idempotency_records by policy_id, action_id, policy_generation, and status (Line 279-281). The table has no index on policy_id, so each policy append performs a sequential scan. Volume is low today, but the scan cost grows with the ledger, which is append-only and never truncated.

Add a supporting index if the ledger is expected to grow.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/alembic/versions/0048_review_revision_policy_authority.py` around
lines 103 - 155, Add a composite index for the deferred custody lookup on
policy_mutation_idempotency_records, covering policy_id, action_id,
policy_generation, and status. Define it alongside the table constraints in the
migration and ensure the downgrade removes it with the table.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/alembic/versions/0048_review_revision_policy_authority.py`:
- Around line 354-366: Update the downgrade flow in
0048_review_revision_policy_authority.py to acquire SHARE ROW EXCLUSIVE locks on
policy_mutation_idempotency_records, review_policies, and revision_policies
before calculating has_custody. Match the locking pattern used by the earlier
authority migrations, then retain the existing custody check and RuntimeError
behavior.
- Around line 167-183: Update the commit-transition comparison in the policy
mutation guard to include created_at in both the new and old immutable column
tuples. Keep the existing status transition and all other identity, digest, and
lineage comparisons unchanged.

In `@backend/tests/test_artifact_admission.py`:
- Around line 572-643: Update suspend_historical_product_custody to allow the
review_policies/review_policy_mutation_custody and
revision_policies/revision_policy_mutation_custody table-trigger pairs used by
this test. Preserve the existing allow-list entries and ensure the helper
accepts these calls before the session.add_all inserts in the custody context.

In `@backend/tests/test_projects.py`:
- Around line 2054-2097: Update the policy handling in create_guide so
review_policy and revision_policy are copied before removing compatibility keys.
Preserve the existing request values and defaults, but ensure
values.pop("sla_hours", None) and values.pop("auto_reject_after_limit", None)
operate on independent dictionaries rather than caller-owned payload data.

In `@docs/operations_project_operating_manual.md`:
- Around line 118-123: Update the policy PUT route guidance to explicitly
instruct clients to construct the replacement If-Match selector from the
returned policy ID, generation, and canonical digest with its sha256 prefix
removed, formatted as a quoted
"<id>.<generation>.<policy_hash_without_sha256_prefix>" value; do not imply that
the API returns the selector directly.

---

Nitpick comments:
In `@backend/alembic/versions/0048_review_revision_policy_authority.py`:
- Around line 103-155: Add a composite index for the deferred custody lookup on
policy_mutation_idempotency_records, covering policy_id, action_id,
policy_generation, and status. Define it alongside the table constraints in the
migration and ensure the downgrade removes it with the table.

In `@backend/app/modules/projects/policy_mutation_replay_repository.py`:
- Around line 22-31: Add docstrings to the public methods find, reserve, and
complete in the policy mutation replay repository, matching the documentation
style used by ProjectRepository. Document each method’s purpose and return
behavior, including reserve’s four possible disposition values: claimed,
mismatch, pending, and replayed.
- Around line 33-92: Update PolicyMutationReplayRepository.reserve to use a
typed disposition—prefer Literal["claimed", "mismatch", "pending", "replayed"]
or a small enum—instead of str, and update the policy mutation service branching
to consume that type while preserving the existing four outcomes.

In `@backend/app/modules/projects/policy_mutation_router.py`:
- Around line 51-59: Document the ordering intent in policy_authorization_actor
with a one-line comment immediately before del key: retain key solely to force
require_policy_mutation_key to run before actor resolution and rate-control
consumption, then discard the validated value.
- Around line 110-113: Update both route handlers’ authorization dependency
annotations to tuple[UUID, ResolvedActor, PreparedAuthorizationService], and add
the same tuple return annotation to policy_authorization. Preserve the existing
three-value unpacking and ensure the required UUID, ResolvedActor, and
PreparedAuthorizationService symbols are imported or reused from their existing
definitions.

In `@backend/app/modules/projects/policy_mutation_service.py`:
- Line 153: Annotate the `_existing` method signature with parameter and return
types, matching the established annotations used by `_replace`. Explicitly type
`response_type` as the Pydantic model class contract required by
`model_validate`, and annotate all remaining parameters and the async return
value consistently with the service’s existing conventions.

In `@backend/scripts/api_contract_e2e.py`:
- Around line 647-654: Expand the docstring for configure_policy_boundaries with
an Args: section documenting client, token, project_id, guide_id, and
guide_version, explicitly noting that guide_version is used for the direct
PaymentPolicy insert. Keep the existing summary line and match the
argument-documentation style used by request_json and
create_policy_bundle_for_guide.

In `@backend/tests/test_alembic.py`:
- Around line 11884-11901: The test’s selector_constraint assertions only verify
presence, not the migration’s changed constraint behavior. Update the assertions
around the upgraded and downgraded shape checks to compare the actual
policy_selection_shape expression via pg_get_constraintdef, or add equivalent
partial-selection writes that succeed after upgrade and fail after downgrade,
while preserving the existing state checks.

In `@backend/tests/test_project_policy_mutations.py`:
- Line 622: Update the test’s service import to include GuideEditBlocked, then
change the pytest.raises assertion around the draft-guide mutation to expect
GuideEditBlocked instead of the broad Exception type while preserving the
existing message match.
- Around line 113-118: Update the test fake’s _Replay.reserve method to return a
configurable disposition and corresponding record, then parameterize the
relevant policy mutation service tests to exercise mismatch, pending, and
replayed outcomes through _replace. Assert each branch’s expected service
behavior while preserving the existing claimed behavior and repository
classification coverage.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ca896127-1a97-475a-a91a-e5bb5d5a28b3

📥 Commits

Reviewing files that changed from the base of the PR and between 2c24c91 and d6e136d.

📒 Files selected for processing (33)
  • .agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/chunks/WS-AUTH-001-12D2-guide-bound-policy-mutations.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/ACTION_CUSTODY.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/DISCOVERY.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/REVIEW_LOG.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/STATUS.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/chunks/WS-XINT-003-02B-policy-mutation-activation.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/reviews/WS-XINT-003-02B-internal-review.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/reviews/WS-XINT-003-02B-pr-trust-bundle.md
  • backend/alembic/versions/0048_review_revision_policy_authority.py
  • backend/app/api/router.py
  • backend/app/modules/authorization/catalogue.py
  • backend/app/modules/authorization/kernel.py
  • backend/app/modules/authorization/prepared.py
  • backend/app/modules/authorization/runtime.py
  • backend/app/modules/projects/models.py
  • backend/app/modules/projects/policy_mutation_replay_repository.py
  • backend/app/modules/projects/policy_mutation_router.py
  • backend/app/modules/projects/policy_mutation_service.py
  • backend/app/modules/projects/repository.py
  • backend/app/modules/projects/schemas.py
  • backend/scripts/api_contract_e2e.py
  • backend/tests/test_alembic.py
  • backend/tests/test_artifact_admission.py
  • backend/tests/test_authorization.py
  • backend/tests/test_policy_identity_lineage.py
  • backend/tests/test_project_policy_mutations.py
  • backend/tests/test_projects.py
  • backend/tests/test_tasks.py
  • docs/operations_authorization_service.md
  • docs/operations_project_operating_manual.md
  • docs/operations_roles_permissions.md
  • docs/spec_authorization_service.md
  • docs/spec_review_lifecycle.md

Comment thread backend/alembic/versions/0048_review_revision_policy_authority.py
Comment thread backend/alembic/versions/0048_review_revision_policy_authority.py
Comment thread backend/tests/test_artifact_admission.py
Comment thread backend/tests/test_projects.py
Comment thread docs/operations_project_operating_manual.md

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/app/modules/projects/policy_mutation_service.py`:
- Around line 277-298: Revalidate the guide version after acquiring the project
guide lock and before prepared.consume(...). In the locked-guide validation
alongside the existing selector precondition, reject when guide.version differs
from guide_snapshot.version, preserving the existing conflict behavior so the
PREP resource cannot use a stale guide_version.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 28a1d657-f11e-4634-8c51-0d0b1bae6b3d

📥 Commits

Reviewing files that changed from the base of the PR and between d6e136d and 1a92f2a.

📒 Files selected for processing (40)
  • .agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/chunks/WS-AUTH-001-12D2-guide-bound-policy-mutations.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/ACTION_CUSTODY.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/DISCOVERY.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/REVIEW_LOG.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/STATUS.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/chunks/WS-XINT-003-02B-policy-mutation-activation.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/reviews/WS-XINT-003-02B-external-review-response.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/reviews/WS-XINT-003-02B-internal-review.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/reviews/WS-XINT-003-02B-pr-trust-bundle.md
  • backend/alembic/versions/0048_review_revision_policy_authority.py
  • backend/app/api/router.py
  • backend/app/modules/authorization/catalogue.py
  • backend/app/modules/authorization/kernel.py
  • backend/app/modules/authorization/prepared.py
  • backend/app/modules/authorization/runtime.py
  • backend/app/modules/projects/models.py
  • backend/app/modules/projects/policy_mutation_replay_repository.py
  • backend/app/modules/projects/policy_mutation_router.py
  • backend/app/modules/projects/policy_mutation_service.py
  • backend/app/modules/projects/repository.py
  • backend/app/modules/projects/schemas.py
  • backend/scripts/api_contract_e2e.py
  • backend/scripts/run_test_lanes.py
  • backend/tests/conftest.py
  • backend/tests/project_create_fixtures.py
  • backend/tests/test_alembic.py
  • backend/tests/test_api_controls.py
  • backend/tests/test_artifact_admission.py
  • backend/tests/test_audit.py
  • backend/tests/test_auth.py
  • backend/tests/test_authorization.py
  • backend/tests/test_policy_identity_lineage.py
  • backend/tests/test_project_policy_mutations.py
  • backend/tests/test_projects.py
  • backend/tests/test_tasks.py
  • docs/operations_authorization_service.md
  • docs/operations_project_operating_manual.md
  • docs/operations_roles_permissions.md
  • docs/spec_authorization_service.md
  • docs/spec_review_lifecycle.md
🚧 Files skipped from review as they are similar to previous changes (28)
  • backend/app/api/router.py
  • .agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/chunks/WS-AUTH-001-12D2-guide-bound-policy-mutations.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/REVIEW_LOG.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/ACTION_CUSTODY.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/reviews/WS-XINT-003-02B-internal-review.md
  • backend/app/modules/projects/repository.py
  • backend/app/modules/authorization/catalogue.py
  • docs/operations_authorization_service.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/DISCOVERY.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/STATUS.md
  • backend/app/modules/projects/schemas.py
  • backend/app/modules/authorization/prepared.py
  • docs/operations_project_operating_manual.md
  • backend/tests/test_artifact_admission.py
  • backend/app/modules/authorization/kernel.py
  • backend/app/modules/authorization/runtime.py
  • backend/tests/test_policy_identity_lineage.py
  • backend/tests/test_authorization.py
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/chunks/WS-XINT-003-02B-policy-mutation-activation.md
  • backend/app/modules/projects/models.py
  • backend/tests/test_projects.py
  • backend/tests/test_alembic.py
  • docs/spec_authorization_service.md
  • backend/app/modules/projects/policy_mutation_router.py
  • backend/tests/test_tasks.py
  • backend/app/modules/projects/policy_mutation_replay_repository.py
  • docs/operations_roles_permissions.md
  • backend/scripts/api_contract_e2e.py

Comment thread backend/app/modules/projects/policy_mutation_service.py
@abiorh-claw
abiorh-claw self-requested a review August 3, 2026 03:34
@abiorh-claw
abiorh-claw self-requested a review August 3, 2026 04:19
@abiorh-claw
abiorh-claw merged commit 25fc27c into main Aug 3, 2026
4 checks passed
@abiorh-claw
abiorh-claw deleted the codex/ws-xint-003-02b-policy-mutation-activation branch August 3, 2026 04:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants