Skip to content

WS-XINT-003-02A: enforce immutable policy identity lineage - #242

Open
Abiorh001 wants to merge 6 commits into
mainfrom
codex/ws-xint-003-02-policy-mutation
Open

WS-XINT-003-02A: enforce immutable policy identity lineage#242
Abiorh001 wants to merge 6 commits into
mainfrom
codex/ws-xint-003-02-policy-mutation

Conversation

@Abiorh001

@Abiorh001 Abiorh001 commented Aug 1, 2026

Copy link
Copy Markdown
Collaborator

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

Chunk

WS-XINT-003-02A — Immutable Policy Identity And Lineage.

Goal and result

ReviewPolicy and RevisionPolicy are now immutable, append-only identities.
ProjectGuide selects exact versions, Task locks those exact facts, and
Submission and CheckerRun copy and database-chain them without treating guide
version as policy version. Both policy mutation actions remain planned and
unavailable.

Design

  • Complete policies carry typed semantics, generation, canonical digest,
    readiness status, and predecessor lineage.
  • Historical policies migrate deterministically as readable
    legacy_incomplete records; missing lease or preference meaning is never
    invented and readiness denies their future activation.
  • Draft guide selections are all-or-none; activation requires complete
    selections and freezes them.
  • Exact project, guide, policy ID, generation, and digest tuples are enforced
    through downstream foreign keys.
  • PostgreSQL rejects policy update, delete, truncate, cross-resource lineage,
    active-selection mutation, and populated downgrade.
  • No compatibility aliases, route, PREP consumer, grant, or ActionId
    activation was added.

Proof

  • Focused migration and lineage tests: 10 passed, 74 deselected.
  • Policy-lineage branch coverage: 9 passed, 100 percent.
  • Direct isolated cross-Task CheckerRun mismatch: 1 passed.
  • Hosted-lane regression corrections for activation, immutable work-context,
    and checker admission: 5 focused cases passed in isolated databases.
  • Ruff, Python compilation, stale contract/wording scans, Markdown links, and
    git diff --check: passed.
  • Hosted GitHub Actions retains the full-suite 78-percent gate and the existing
    targeted 90-percent subsystem gate; no threshold or failure behavior changed.
  • The new policy-lineage test module has explicit shared_foundations semantic-
    lane custody; the initial fail-closed missing-inventory result was corrected.

Review

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

External review

GitHub Actions and CodeRabbit must review the exact final PR head. Every valid
comment or failing check must be resolved before human merge.

CodeRabbit's complete first-head review produced four valid points across three
inline comments: policy identity metadata, scoped row locking, fixture
activation ordering, and shared test semantics. All are fixed and recorded in
WS-XINT-003-02A-external-review-response.md. Later incremental attempts were
rate-limited; exact-head Agent Gates and Backend are the authoritative checks.

Remaining risk and follow-up

This chunk establishes identity and lineage but deliberately activates no
policy writer. WS-XINT-003-02B installs the sole authorized mutation path only
after 02A merges and the user explicitly starts that next chunk.

Human review focus

Confirm deterministic legacy handling, immutable exact identity selection,
complete downstream FK chaining, absence of invented semantics, and zero
runtime policy-action activation.

Human merge ownership

Only the human may merge this PR.

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This change introduces immutable review and revision policy identities based on ID, generation, and hash values. It migrates downstream policy locks, validates exact lineage, updates tests and documentation, and separates immutable persistence in 02A from future mutation activation in 02B.

Changes

Policy lineage and staged activation

Layer / File(s) Summary
Immutable policy persistence and validation
backend/alembic/..., backend/app/modules/projects/...
Policies now use immutable generations, canonical hashes, semantic status, supersession links, exact guide selections, and database-enforced lineage constraints.
Downstream policy propagation
backend/app/modules/tasks/*, backend/app/modules/checkers/*
Tasks, submissions, and checker runs store and validate policy ID, generation, and hash triples. Responses and audit payloads use the new provenance fields.
Migration, API, and regression coverage
backend/tests/*, backend/scripts/*, docs/*, examples/terminal_benchmark/*
Migration, lineage, API, redaction, immutability, and deprecated-field tests and documentation reflect the new policy model.
02A/02B planning and custody contracts
.agent-loop/...
Planning artifacts split immutable persistence from PREP-bound mutation activation and define ownership, sequencing, review gates, and stop conditions.

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

Sequence Diagram(s)

sequenceDiagram
  participant ProjectGuide
  participant PolicyRepository
  participant TaskService
  participant CheckerService
  ProjectGuide->>PolicyRepository: select exact policy identity
  TaskService->>PolicyRepository: resolve and validate policy lineage
  TaskService->>CheckerService: persist locked policy identity
  CheckerService->>CheckerService: validate and expose authorized provenance
Loading

Possibly related PRs

Suggested reviewers: abiorh-claw

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 53.75% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The description explains the goal, design, evidence, review status, risks, follow-up, and human focus, but omits many required template sections and structured fields. Add the required trust-bundle headings and details, including scope, product behavior, commands and results, acceptance proof, test delta, reviewer tables, CI gates, and ownership checkboxes.
✅ Passed checks (3 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title clearly identifies the chunk and its main change: enforcing immutable policy identity lineage.
✨ 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-02-policy-mutation

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.

@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: 3

🧹 Nitpick comments (1)
backend/tests/test_projects.py (1)

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

Build the review-policy values once, then reuse them.

The explicit keyword arguments at lines 2057-2062 repeat the defaults used for the digest at lines 2038-2043. If a caller passes review_policy with any of those keys, ReviewPolicy(...) raises TypeError: got multiple values for keyword argument. A single merged mapping removes that failure mode and keeps the digest and the row in exact agreement.

♻️ Proposed refactor
-            values.pop("sla_hours", None)
-            review_hash = policy_digest(
-                "review",
-                ReviewPolicySemantics.model_validate(
-                    {
-                        "review_preference_window_seconds": 3600,
-                        "review_lease_duration_seconds": 1800,
-                        "max_active_review_leases_per_reviewer": 1,
-                        "self_review_allowed": False,
-                        "reject_policy": "close_task",
-                        "finding_evidence_requirement": "optional",
-                        **values,
-                    }
-                ),
-            )
+            values.pop("sla_hours", None)
+            values = {
+                "review_preference_window_seconds": 3600,
+                "review_lease_duration_seconds": 1800,
+                "max_active_review_leases_per_reviewer": 1,
+                "self_review_allowed": False,
+                "reject_policy": "close_task",
+                "finding_evidence_requirement": "optional",
+                **values,
+            }
+            review_hash = policy_digest(
+                "review", ReviewPolicySemantics.model_validate(values)
+            )
             review_id = str(uuid4())
             session.add(
                 ReviewPolicy(
                     id=review_id,
                     project_id=project_id,
                     guide_version=guide["version"],
                     policy_generation=1,
                     policy_hash=review_hash,
                     semantics_status="complete",
-                    review_preference_window_seconds=3600,
-                    review_lease_duration_seconds=1800,
-                    max_active_review_leases_per_reviewer=1,
-                    self_review_allowed=False,
-                    reject_policy="close_task",
-                    finding_evidence_requirement="optional",
                     **values,
                 )
             )
🤖 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_projects.py` around lines 2033 - 2064, Build one merged
review-policy values mapping from the defaults and incoming values before
computing the digest, then reuse that mapping for both
ReviewPolicySemantics.model_validate and ReviewPolicy in this test setup. Remove
the duplicated explicit keyword arguments from ReviewPolicy so caller-provided
keys cannot be passed twice and the digest and persisted row remain identical.
🤖 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/models.py`:
- Around line 423-455: Add SHA-256 hash-shape CheckConstraints for both
ReviewPolicy and RevisionPolicy policy_hash columns. Update
ReviewPolicy.__table_args__ with the established constraint pattern and name it
ck_review_policies_policy_hash_shape; add the equivalent constraint to
RevisionPolicy.__table_args__ named ck_revision_policies_policy_hash_shape,
preserving the required sha256:... format and existing constraints.

In `@backend/app/modules/projects/repository.py`:
- Around line 823-867: Scope the row locks in lock_review_policy and
lock_revision_policy to their respective policy tables by passing
of=ReviewPolicy and of=RevisionPolicy to with_for_update(). Keep the existing
joins and filtering unchanged so only the selected policy row is locked, not the
joined ProjectGuide row.

In `@backend/tests/test_artifact_admission.py`:
- Around line 632-645: The fixture setup around ProjectGuide must avoid flushing
an active guide with null policy selections and must prevent the immutability
trigger from rejecting the later update. Create the guide with draft status,
persist both policies and all selection fields before activation, and update the
row to active in the same final step; alternatively, explicitly suppress the
selection guard for this fixture while retaining valid trigger behavior.

---

Nitpick comments:
In `@backend/tests/test_projects.py`:
- Around line 2033-2064: Build one merged review-policy values mapping from the
defaults and incoming values before computing the digest, then reuse that
mapping for both ReviewPolicySemantics.model_validate and ReviewPolicy in this
test setup. Remove the duplicated explicit keyword arguments from ReviewPolicy
so caller-provided keys cannot be passed twice and the digest and persisted row
remain identical.
🪄 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: d12a4937-0fbd-44e8-896d-ab03ff181604

📥 Commits

Reviewing files that changed from the base of the PR and between ad8da7e and 87f3343.

📒 Files selected for processing (42)
  • .agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/chunks/WS-AUTH-001-12D2-guide-bound-policy-mutations.md
  • .agent-loop/initiatives/WS-REV-001-review-revision-lifecycle/chunks/WS-REV-001-03P-review-revision-policy-persistence.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/CHUNK_MAP.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/PLAN.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-02-policy-mutation-activation.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/chunks/WS-XINT-003-02A-policy-identity-lineage.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-02A-internal-review.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/reviews/WS-XINT-003-02A-pr-trust-bundle.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/reviews/WS-XINT-003-02A-preimplementation-review.md
  • backend/alembic/versions/0046_immutable_review_revision_policy_lineage.py
  • backend/app/modules/checkers/models.py
  • backend/app/modules/checkers/runner.py
  • backend/app/modules/checkers/schemas.py
  • backend/app/modules/checkers/service.py
  • backend/app/modules/projects/models.py
  • backend/app/modules/projects/policy_lineage.py
  • backend/app/modules/projects/repository.py
  • backend/app/modules/projects/schemas.py
  • backend/app/modules/projects/service.py
  • backend/app/modules/tasks/models.py
  • backend/app/modules/tasks/schemas.py
  • backend/app/modules/tasks/service.py
  • backend/scripts/api_contract_e2e.py
  • backend/scripts/week2_api_e2e.py
  • backend/tests/conftest.py
  • backend/tests/test_alembic.py
  • backend/tests/test_artifact_admission.py
  • backend/tests/test_checkers.py
  • backend/tests/test_policy_identity_lineage.py
  • backend/tests/test_projects.py
  • backend/tests/test_tasks.py
  • docs/architecture_data_model.md
  • docs/glossary.md
  • docs/spec_chunk_5_submission_packet_foundation.md
  • docs/spec_chunk_6_checker_contract_records.md
  • docs/spec_review_lifecycle.md
  • docs/template_project_guide.md
  • examples/terminal_benchmark/terminal_benchmark_api_e2e.py

Comment thread backend/app/modules/projects/models.py
Comment thread backend/app/modules/projects/repository.py
Comment thread backend/tests/test_artifact_admission.py

@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.

🧹 Nitpick comments (1)
backend/tests/test_projects.py (1)

173-184: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Strengthen the schema-contract assertion.

This test checks text fragments only. It would still pass if AND changed to OR, if the hash pattern became broader, or if an unsupported status were added. Compare the normalized compiled expression with the migration contract, or add PostgreSQL cases that reject invalid generations, hashes, and statuses.

🤖 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_projects.py` around lines 173 - 184, Strengthen
test_policy_identity_shape_metadata_matches_migration_contract by validating the
complete normalized constraint expression rather than independent SQL fragments.
Ensure the assertion preserves the migration contract’s AND semantics, exact
sha256 hash pattern, positive policy_generation requirement, and only the
supported complete and legacy_incomplete statuses; alternatively add
PostgreSQL-backed cases that reject invalid generations, hashes, and statuses.
🤖 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.

Nitpick comments:
In `@backend/tests/test_projects.py`:
- Around line 173-184: Strengthen
test_policy_identity_shape_metadata_matches_migration_contract by validating the
complete normalized constraint expression rather than independent SQL fragments.
Ensure the assertion preserves the migration contract’s AND semantics, exact
sha256 hash pattern, positive policy_generation requirement, and only the
supported complete and legacy_incomplete statuses; alternatively add
PostgreSQL-backed cases that reject invalid generations, hashes, and statuses.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5849b5ed-9e12-4449-94e9-f64ded2dde4f

📥 Commits

Reviewing files that changed from the base of the PR and between 87f3343 and 133f997.

📒 Files selected for processing (12)
  • .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/chunks/WS-XINT-003-02A-policy-identity-lineage.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/reviews/WS-XINT-003-02A-external-review-response.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/reviews/WS-XINT-003-02A-internal-review.md
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/reviews/WS-XINT-003-02A-pr-trust-bundle.md
  • backend/app/modules/projects/models.py
  • backend/app/modules/projects/repository.py
  • backend/app/modules/projects/service.py
  • backend/scripts/run_test_lanes.py
  • backend/tests/test_artifact_admission.py
  • backend/tests/test_projects.py
  • backend/tests/test_tasks.py
🚧 Files skipped from review as they are similar to previous changes (7)
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/reviews/WS-XINT-003-02A-pr-trust-bundle.md
  • backend/app/modules/projects/repository.py
  • backend/tests/test_tasks.py
  • .agent-loop/initiatives/WS-XINT-003-rev-auth-end-to-end/chunks/WS-XINT-003-02A-policy-identity-lineage.md
  • backend/app/modules/projects/models.py
  • backend/tests/test_artifact_admission.py
  • backend/app/modules/projects/service.py

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.

1 participant