Skip to content

Implement post-submit setup derivation#88

Open
Abiorh001 wants to merge 2 commits into
mainfrom
codex/ws-pol-002-02-post-submit-derivation
Open

Implement post-submit setup derivation#88
Abiorh001 wants to merge 2 commits into
mainfrom
codex/ws-pol-002-02-post-submit-derivation

Conversation

@Abiorh001

@Abiorh001 Abiorh001 commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

PR Trust Bundle: WS-POL-002-02

Chunk

WS-POL-002-02 - Post-Submit Derivation Agent And Resumable Setup Integration

Goal

Add setup-time post-submit checker derivation and compilation after
submission artifact policy approval and pre-submit checker compilation, without
introducing runtime agent judgment or per-task checker generation.

Human-Approved Intent

Post-submit checkers must follow the same shape as pre-submit:

Project guide/source material
-> setup-time derivation agent
-> trusted Workstream compiler
-> project PostSubmitCheckerPolicy
-> tasks later lock references
-> finalized submissions execute deterministic checkers

The agent derives a constrained specification during setup. Workstream compiles
and owns the deterministic checker policy. The agent never judges worker
submissions at runtime.

What Changed

  • Added post-submit derivation models to the project-agent interface.
  • Extended the OpenAI Agents SDK adapter with a post-submit derivation prompt and structured output parsing.
  • Extended project setup continuation after submission artifact policy approval and pre-submit compile.
  • Added post-submit setup-run statuses and persisted output metadata.
  • Added migration 0014_post_submit_setup for post-submit setup provenance.
  • Added generated post-submit policy provenance fields:
    • guide id/version
    • source snapshot id/hash
    • effective project policy id/hash
    • pre-submit checker policy id/bundle hash
    • lifecycle and setup approval provenance
  • Enforced activation rejection for compiled-only or non-setup-approved post-submit policies.
  • Added stale continuation guards for enqueue bookkeeping, worker start, in-flight derivation, terminal state updates, and duplicate worker retries.
  • Updated docs to describe the setup continuation and the next approval chunk boundary.

Design Chosen

The existing project setup queue and worker were extended. No disconnected
post-submit-only queue was added.

The setup pipeline now continues like this:

policy_draft_ready
-> setup-authorized submission artifact policy approval
-> effective project submission artifact policy
-> compiled project pre-submit checker policy
-> enqueue post-submit setup continuation
-> PostSubmitCheckerPolicyDerivationAgent
-> trusted post-submit compiler
-> compiled project PostSubmitCheckerPolicy pending setup approval

The post-submit policy remains project-scoped. Tasks will later lock the
project policy reference; they do not derive or compile their own checker
bundle.

Alternatives Rejected

  • Runtime agent judgment: rejected. Runtime executes deterministic checkers only.
  • Per-task checker derivation: rejected. Policy is project-scoped.
  • Manual post-submit policy in guide payloads: rejected. Generated setup output owns this path.
  • Separate post-submit-only queue: rejected. The current project setup queue is the correct boundary.
  • Arbitrary generated checker code: rejected for v0.1.

Scope Control

No task runtime module changes, frontend/demo work, payment, reputation,
blockchain, marketplace, or settlement work were included.

The route change is docstring-only to remove stale OpenAPI wording that implied
manual post-submit policy updates.

Product Behavior

Setup-authorized admins/project managers can approve the submission artifact
policy. That approval creates the effective project policy and compiled
pre-submit checker bundle, then resumes setup into post-submit derivation.

Unsupported post-submit checker requirements block setup with bounded
operator-visible details. Workers and reviewers do not receive internal setup
defects as product review decisions.

Guide activation still requires setup approval of the compiled post-submit
policy. This chunk creates the compiled generated output; WS-POL-002-03
implements the server-owned visibility and approval surface.

Acceptance Criteria Proof

  • Derivation runs only after submission artifact policy approval and pre-submit compile.
  • Blocked sufficiency prevents post-submit derivation.
  • Unsupported required checker gaps block setup.
  • Unknown checkers fail closed.
  • Successful derivation creates compiled project PostSubmitCheckerPolicy.
  • Activation rejects compiled-only post-submit policies.
  • Provenance binds guide, source snapshot, effective policy, and pre-submit checker policy.
  • Hostile source is treated as data and cannot override Workstream defaults.
  • API-visible setup summaries are bounded and redacted.
  • Stale workers cannot insert stale policy rows.
  • Stale enqueue success/failure bookkeeping cannot mutate a newer setup run.
  • Duplicate worker failures cannot regress an already compiled setup run.

Tests/Checks Run

cd backend && .venv/bin/pytest tests/test_projects.py -q -k "post_submit_continuation or corrected_submission_artifact_policy or stale_in_flight_post_submit or status_update_rejects_stale_continuation or enqueue_bookkeeping_rejects_stale or compiled_post_submit_setup_run_does_not_regress or activation_rejects_compiled_post_submit or approved_by_non_setup_role or unsupported_checker_gap or unknown_checker_blocks or setup_summary_redacts"
cd backend && .venv/bin/pytest tests/test_projects.py tests/test_agent_runtime.py -q
cd backend && .venv/bin/pytest tests/test_alembic.py -q
cd backend && .venv/bin/ruff check app/adapters/project_agents/openai_agent_sdk.py app/interfaces/project_agents.py app/workers/project_setup.py app/modules/projects/setup_queue.py app/modules/projects/service.py app/modules/projects/schemas.py app/modules/projects/models.py app/modules/projects/repository.py app/modules/projects/router.py tests/test_projects.py tests/test_agent_runtime.py tests/test_alembic.py
cd backend && .venv/bin/python -m py_compile app/adapters/project_agents/openai_agent_sdk.py app/interfaces/project_agents.py app/workers/project_setup.py app/modules/projects/setup_queue.py app/modules/projects/service.py app/modules/projects/schemas.py app/modules/projects/models.py app/modules/projects/repository.py app/modules/projects/router.py tests/test_projects.py tests/test_agent_runtime.py tests/test_alembic.py
cd backend && .venv/bin/docstr-coverage --config .docstr.yaml
python3 scripts/check_stale_workstream_wording.py
python3 scripts/check_markdown_links.py
python3 scripts/test_agent_gates.py
python3 scripts/check_loop_memory_state.py
git diff --check

Result summary:

  • Focused stale/setup suite: 13 passed.
  • Full project and agent-runtime suite: 229 passed.
  • Alembic suite: 6 passed.
  • Ruff, py_compile, docstring coverage, stale wording, Markdown links, agent gates, loop memory, and diff whitespace checks passed.

Reviewer Results

Internal review evidence:

  • .agent-loop/initiatives/WS-POL-002-post-submit-checker-foundation/reviews/WS-POL-002-02-internal-review-evidence.md

Reviewed code SHA: 9179f9dced4b5b58c298cb1f93149c26d6d2b6c3

Reviewed at: 2026-07-10T05:27:44Z

Reviewer Result Blocking findings Notes
senior engineering PASS WITH LOW RISKS None Duplicate worker regression fixed; low future crash-window hardening noted.
QA/test PASS None Stale enqueue, stale in-flight, status update, and duplicate worker tests cover prior failures.
security/auth PASS None Role, provenance, redaction, and fail-closed checks passed.
product/ops PASS WITH LOW RISKS None Setup defects stay operator-visible and separate from review decisions.
architecture PASS WITH LOW RISKS None Setup-time/project-scoped boundaries preserved.
docs PASS WITH LOW RISKS None Wording fixes applied.
reuse/dedup PASS WITH LOW RISKS None Low future extraction opportunities accepted.
test delta PASS None No weakened/skipped coverage.
CI integrity PASS None No gate weakening.

External Review

External review is pending for this PR. CodeRabbit and GitHub Actions must run
after the branch is pushed, and any actionable comments must be handled in a
separate external review response file.

Remaining Risks

  • A narrow fail-closed crash window remains between post-submit policy commit
    and setup-run compiled-status write. Retry/operator repair can recover; later
    hardening can make first compiled policy win by provenance.
  • Provenance validation appears in a few service locations for different
    exception semantics. This is accepted for this chunk but should be extracted
    if setup policy grows further.

Human Review Focus

  • Confirm the agent derives setup policy only.
  • Confirm unsupported checker requirements fail closed.
  • Confirm no runtime submission judgment is delegated to an agent.
  • Confirm tasks are still not generating their own checker policies.

Human Merge Ownership

Only the user can approve and merge this PR. Codex must not merge it without
explicit user approval for that specific PR.

Summary by CodeRabbit

  • New Features

    • Added automated post-submit checker policy derivation during project setup.
    • Added setup continuation handling with resumable processing, duplicate protection, and stale-run safeguards.
    • Exposed post-submit setup status, generated policy references, lifecycle, and approval metadata.
    • Added stricter activation checks requiring matching, approved policy provenance.
  • Bug Fixes

    • Prevented unsupported or mismatched checker policies from activating.
    • Improved safe redaction and handling of hostile or untrusted derivation content.
  • Documentation

    • Updated setup instructions, architecture references, glossary entries, and operating guidance for post-submit policy workflows.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds setup-time post-submit checker derivation and compilation, persists provenance-bound policy outputs, introduces resumable Celery setup continuations with stale-worker handling, removes client-supplied post-submit policy inputs, and updates activation checks, documentation, planning state, and tests.

Changes

Post-submit checker derivation

Layer / File(s) Summary
Policy contract and persistence
backend/app/interfaces/project_agents.py, backend/app/modules/projects/models.py, backend/alembic/versions/*, backend/app/modules/projects/schemas.py, backend/app/modules/projects/repository.py
Adds structured derivation contracts, provenance and lifecycle fields, setup-run outputs and statuses, migration safeguards, and idempotent repository persistence.
Agent derivation and trusted compilation
backend/app/adapters/project_agents/openai_agent_sdk.py, backend/app/modules/projects/service.py, backend/tests/test_agent_runtime.py, backend/tests/test_projects.py
Derives bounded checker specifications through the agent runtime, validates evidence and checker names, compiles deterministic policies, and redacts stored summaries.
Resumable setup continuation
backend/app/modules/projects/setup_queue.py, backend/app/workers/project_setup.py, backend/app/modules/projects/service.py, backend/tests/test_projects.py
Enqueues and runs post-submit setup continuations with locked payload validation, stale continuation handling, failure states, and idempotent redelivery behavior.
Activation and API enforcement
backend/app/modules/projects/schemas.py, backend/app/modules/projects/service.py, backend/app/modules/projects/router.py, backend/tests/test_projects.py
Removes manual post-submit policy request fields, exposes generated setup output, and requires matching compiled and approved provenance before activation.
Workflow documentation and review records
.agent-loop/**, README.md, docs/*
Updates initiative state, review evidence, setup workflow documentation, operator guidance, data-model descriptions, and post-submit derivation contracts.

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

Possibly related issues

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 64.75% 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 is concise and accurately summarizes the main change in the PR.
Description check ✅ Passed The description covers the main template sections and includes goal, changes, tests, review, risks, and ownership details.
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
📝 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-pol-002-02-post-submit-derivation

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 (3)
backend/app/workers/project_setup.py (1)

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

Duplicated stale-recovery try/except across error branches.

The ProjectServiceError (327-368) and Exception (387-420) branches each nest an identical try: update_project_setup_run_status(...) / except StaleProjectSetupContinuation: ... pattern to detect a concurrent successful compile before overwriting status. Extracting a small helper (e.g. _record_terminal_status_or_recover(...)) would remove the duplication and reduce the risk of the two branches diverging over time.

🤖 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/workers/project_setup.py` around lines 298 - 425, Extract the
duplicated terminal-status update and stale-continuation recovery logic from the
ProjectServiceError and generic Exception branches into a helper such as
_record_terminal_status_or_recover. Have it call update_project_setup_run_status
with the supplied status, error details, and continuation policy identifiers,
return the post_submit_policy_compiled recovery result when applicable, and
handle StaleProjectSetupContinuation consistently; update both branches to use
the helper while preserving their existing fallback responses and logging.
backend/alembic/versions/0014_post_submit_setup_continuation.py (1)

95-115: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Multi-column FKs use raw string names instead of op.f(), inconsistent with line 89.

Only the single-column guide_id FK (Line 89) is wrapped in op.f(); the three composite hash-locking FKs (lines 96, 102, 109) use plain literal names. If a naming convention with an fk pattern is configured, these plain names may be silently overridden by the convention-derived name (ignoring the string you supplied), making the downgrade's matching drop constraint if exists fk_checker_policies_source_snapshot_hash etc. (lines 313-335) potentially incorrect too — again likely masked by cascading DROP COLUMN cleanup.

🤖 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/0014_post_submit_setup_continuation.py` around lines
95 - 115, Wrap the names of all three composite foreign keys in the
upgrade—fk_checker_policies_source_snapshot_hash,
fk_checker_policies_effective_policy_hash, and
fk_checker_policies_pre_submit_checker_hash—with op.f(), matching the guide_id
foreign key. Update the corresponding downgrade drop_constraint names to use
op.f() as well, ensuring both upgrade and downgrade resolve the configured
naming convention consistently.
backend/app/modules/projects/setup_queue.py (1)

95-118: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider deduplicating per-task Celery config sync.

Each task now repeats the same broker/result-backend/eager-propagation assignment block. As more setup continuation tasks get added, this will keep growing linearly and risks the two tasks drifting out of sync if one gets updated and the other doesn't.

♻️ Proposed refactor
 def _sync_task_settings() -> None:
     """Sync mutable Celery task settings from the current test/runtime config."""
     from app.workers.project_setup import (
         run_post_submit_setup_continuation,
         run_pre_submit_setup_pipeline,
     )

     settings = get_settings()
-    if settings.celery_broker_url is not None:
-        run_pre_submit_setup_pipeline.app.conf.broker_url = settings.celery_broker_url
-        run_post_submit_setup_continuation.app.conf.broker_url = settings.celery_broker_url
-    elif settings.celery_task_always_eager:
-        run_pre_submit_setup_pipeline.app.conf.broker_url = "memory://"
-        run_post_submit_setup_continuation.app.conf.broker_url = "memory://"
-    run_pre_submit_setup_pipeline.app.conf.result_backend = settings.celery_result_backend_url
-    run_pre_submit_setup_pipeline.app.conf.task_always_eager = settings.celery_task_always_eager
-    run_pre_submit_setup_pipeline.app.conf.task_eager_propagates = True
-    run_post_submit_setup_continuation.app.conf.result_backend = (
-        settings.celery_result_backend_url
-    )
-    run_post_submit_setup_continuation.app.conf.task_always_eager = (
-        settings.celery_task_always_eager
-    )
-    run_post_submit_setup_continuation.app.conf.task_eager_propagates = True
+    for task in (run_pre_submit_setup_pipeline, run_post_submit_setup_continuation):
+        if settings.celery_broker_url is not None:
+            task.app.conf.broker_url = settings.celery_broker_url
+        elif settings.celery_task_always_eager:
+            task.app.conf.broker_url = "memory://"
+        task.app.conf.result_backend = settings.celery_result_backend_url
+        task.app.conf.task_always_eager = settings.celery_task_always_eager
+        task.app.conf.task_eager_propagates = True
🤖 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/setup_queue.py` around lines 95 - 118, Refactor
_sync_task_settings to deduplicate the identical Celery configuration
assignments for run_pre_submit_setup_pipeline and
run_post_submit_setup_continuation. Define a shared collection of these task
objects and apply broker_url, result_backend, task_always_eager, and
task_eager_propagates uniformly in one loop, preserving the existing memory://
fallback behavior.
🤖 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 @.agent-loop/REVIEW_LOG.md:
- Line 23: Update the result entry in REVIEW_LOG.md so it does not claim
external review was addressed while that gate remains pending; either state that
external review is still pending or provide a verifiable link to the completed
external-review evidence before marking it complete.

In `@backend/app/modules/projects/models.py`:
- Around line 147-176: Add a backfill path in migration 0014_post_submit_setup
before enforcing NOT NULL on the new checker policy columns. Populate existing
checker_policies rows with valid derived or default values, then apply the
constraints; alternatively, explicitly enforce and document that the table must
be reset before upgrading. Update the migration logic and related model fields
consistently.

In `@backend/app/workers/project_setup.py`:
- Around line 273-297: Normalize every “post_submit_policy_compiled” return in
the setup flow, including the already_compiled branch and the success path in
run_post_submit_checker_policy_compilation, to include both
post_submit_checker_policy_id and idempotent. Obtain the existing policy ID for
already_compiled, use idempotent=True only for that branch and False for newly
compiled results, and ensure the race-recovery returns match the same shape.

---

Nitpick comments:
In `@backend/alembic/versions/0014_post_submit_setup_continuation.py`:
- Around line 95-115: Wrap the names of all three composite foreign keys in the
upgrade—fk_checker_policies_source_snapshot_hash,
fk_checker_policies_effective_policy_hash, and
fk_checker_policies_pre_submit_checker_hash—with op.f(), matching the guide_id
foreign key. Update the corresponding downgrade drop_constraint names to use
op.f() as well, ensuring both upgrade and downgrade resolve the configured
naming convention consistently.

In `@backend/app/modules/projects/setup_queue.py`:
- Around line 95-118: Refactor _sync_task_settings to deduplicate the identical
Celery configuration assignments for run_pre_submit_setup_pipeline and
run_post_submit_setup_continuation. Define a shared collection of these task
objects and apply broker_url, result_backend, task_always_eager, and
task_eager_propagates uniformly in one loop, preserving the existing memory://
fallback behavior.

In `@backend/app/workers/project_setup.py`:
- Around line 298-425: Extract the duplicated terminal-status update and
stale-continuation recovery logic from the ProjectServiceError and generic
Exception branches into a helper such as _record_terminal_status_or_recover.
Have it call update_project_setup_run_status with the supplied status, error
details, and continuation policy identifiers, return the
post_submit_policy_compiled recovery result when applicable, and handle
StaleProjectSetupContinuation consistently; update both branches to use the
helper while preserving their existing fallback responses and logging.
🪄 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: 5b1b81c9-c0ad-4ee8-9b69-bbb4895a3c1a

📥 Commits

Reviewing files that changed from the base of the PR and between ed52c21 and 76232cc.

📒 Files selected for processing (27)
  • .agent-loop/LOOP_STATE.md
  • .agent-loop/REVIEW_LOG.md
  • .agent-loop/WORK_QUEUE.md
  • .agent-loop/initiatives/WS-POL-002-post-submit-checker-foundation/CHUNK_MAP.md
  • .agent-loop/initiatives/WS-POL-002-post-submit-checker-foundation/STATUS.md
  • .agent-loop/initiatives/WS-POL-002-post-submit-checker-foundation/chunks/WS-POL-002-02-post-submit-derivation-agent.md
  • .agent-loop/initiatives/WS-POL-002-post-submit-checker-foundation/chunks/WS-POL-002-03-post-submit-policy-approval-visibility.md
  • .agent-loop/initiatives/WS-POL-002-post-submit-checker-foundation/reviews/WS-POL-002-02-internal-review-evidence.md
  • .agent-loop/initiatives/WS-POL-002-post-submit-checker-foundation/reviews/WS-POL-002-02-pr-trust-bundle.md
  • README.md
  • backend/alembic/versions/0014_post_submit_setup_continuation.py
  • backend/app/adapters/project_agents/openai_agent_sdk.py
  • backend/app/interfaces/project_agents.py
  • backend/app/modules/projects/models.py
  • backend/app/modules/projects/repository.py
  • backend/app/modules/projects/router.py
  • backend/app/modules/projects/schemas.py
  • backend/app/modules/projects/service.py
  • backend/app/modules/projects/setup_queue.py
  • backend/app/workers/project_setup.py
  • backend/tests/test_agent_runtime.py
  • backend/tests/test_alembic.py
  • backend/tests/test_projects.py
  • docs/architecture_checker_framework.md
  • docs/architecture_data_model.md
  • docs/glossary.md
  • docs/operations_project_operating_manual.md

Comment thread .agent-loop/REVIEW_LOG.md
- reuse/dedup
- test delta

Result: PASS after fixes; external review addressed; GitHub checks passed.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Do not mark external review complete while it is still pending.

This entry says “external review addressed,” but the supplied PR context explicitly says external review remains pending. Update the result to reflect the pending gate, or link the actual external-review evidence before recording completion.

🤖 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 @.agent-loop/REVIEW_LOG.md at line 23, Update the result entry in
REVIEW_LOG.md so it does not claim external review was addressed while that gate
remains pending; either state that external review is still pending or provide a
verifiable link to the completed external-review evidence before marking it
complete.

Comment on lines +147 to +176
guide_id: Mapped[str] = mapped_column(ForeignKey("project_guides.id"), nullable=False, index=True)
guide_version: Mapped[str] = mapped_column(String(50), nullable=False)
source_snapshot_id: Mapped[str] = mapped_column(
ForeignKey("guide_source_snapshots.id"),
nullable=False,
index=True,
)
source_snapshot_hash: Mapped[str] = mapped_column(String(71), nullable=False)
effective_policy_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
effective_policy_hash: Mapped[str] = mapped_column(String(71), nullable=False, index=True)
pre_submit_checker_policy_id: Mapped[str] = mapped_column(
String(36),
nullable=False,
index=True,
)
pre_submit_checker_bundle_hash: Mapped[str] = mapped_column(
String(71),
nullable=False,
index=True,
)
required_checkers: Mapped[list[str]] = mapped_column(JSON, nullable=False, default=list)
warning_checkers: Mapped[list[str]] = mapped_column(JSON, nullable=False, default=list)
blocking_severities: Mapped[list[str]] = mapped_column(JSON, nullable=False, default=list)
policy_hash: Mapped[str | None] = mapped_column(String(71), index=True)
policy_body: Mapped[dict | None] = mapped_column(JSON)
lifecycle_status: Mapped[str] = mapped_column(String(30), nullable=False, default="compiled")
approved_by_role: Mapped[str | None] = mapped_column(String(50))
approved_by_actor: Mapped[str | None] = mapped_column(String(100))
approved_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
created_by: Mapped[str] = mapped_column(String(100), nullable=False)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect migration 0014 for how new NOT NULL columns on checker_policies are added/backfilled.
fd -t f '0014_post_submit_setup' backend/alembic/versions --exec cat -n {}

Repository: Flow-Research/workstream

Length of output: 14121


Add a backfill path before making these columns NOT NULL

0014_post_submit_setup currently aborts on any existing checker_policies rows instead of backfilling these fields. If this table is non-empty in upgrade environments, the migration will fail; add a migration path for existing data or make the reset requirement explicit.

🤖 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/models.py` around lines 147 - 176, Add a
backfill path in migration 0014_post_submit_setup before enforcing NOT NULL on
the new checker policy columns. Populate existing checker_policies rows with
valid derived or default values, then apply the constraints; alternatively,
explicitly enforce and document that the table must be reset before upgrading.
Update the migration logic and related model fields consistently.

Comment on lines +273 to +297
if start_status == "already_compiled":
return {"status": "post_submit_policy_compiled", "idempotent": True}
policy, _, summary = await service.run_post_submit_checker_policy_derivation_agent(
actor,
project_id,
guide_id,
source_snapshot_id,
effective_policy_id,
pre_submit_checker_policy_id,
setup_run_id,
)
await service.update_project_setup_run_status(
setup_run_id,
status="post_submit_policy_compiled",
current_step="post_submit_checker_policy_compilation",
output_post_submit_checker_policy_id=policy.id,
post_submit_derivation_summary=summary
| {"post_submit_checker_policy_id": policy.id},
continuation_effective_policy_id=effective_policy_id,
continuation_pre_submit_checker_policy_id=pre_submit_checker_policy_id,
)
return {
"status": "post_submit_policy_compiled",
"post_submit_checker_policy_id": policy.id,
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Inconsistent return-dict shape for post_submit_policy_compiled.

The "already_compiled" early return (Line 274) omits post_submit_checker_policy_id, while the success path (lines 294-297) omits idempotent, yet the race-recovery paths (345-352, 397-404) include both keys. Callers that index either key unconditionally on a differently-shaped branch will hit a KeyError.

🔧 Proposed fix
                 if start_status == "already_compiled":
-                    return {"status": "post_submit_policy_compiled", "idempotent": True}
+                    return {
+                        "status": "post_submit_policy_compiled",
+                        "idempotent": True,
+                        "post_submit_checker_policy_id": None,
+                    }
-                return {
-                    "status": "post_submit_policy_compiled",
-                    "post_submit_checker_policy_id": policy.id,
-                }
+                return {
+                    "status": "post_submit_policy_compiled",
+                    "idempotent": False,
+                    "post_submit_checker_policy_id": policy.id,
+                }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if start_status == "already_compiled":
return {"status": "post_submit_policy_compiled", "idempotent": True}
policy, _, summary = await service.run_post_submit_checker_policy_derivation_agent(
actor,
project_id,
guide_id,
source_snapshot_id,
effective_policy_id,
pre_submit_checker_policy_id,
setup_run_id,
)
await service.update_project_setup_run_status(
setup_run_id,
status="post_submit_policy_compiled",
current_step="post_submit_checker_policy_compilation",
output_post_submit_checker_policy_id=policy.id,
post_submit_derivation_summary=summary
| {"post_submit_checker_policy_id": policy.id},
continuation_effective_policy_id=effective_policy_id,
continuation_pre_submit_checker_policy_id=pre_submit_checker_policy_id,
)
return {
"status": "post_submit_policy_compiled",
"post_submit_checker_policy_id": policy.id,
}
if start_status == "already_compiled":
return {
"status": "post_submit_policy_compiled",
"idempotent": True,
"post_submit_checker_policy_id": None,
}
policy, _, summary = await service.run_post_submit_checker_policy_derivation_agent(
actor,
project_id,
guide_id,
source_snapshot_id,
effective_policy_id,
pre_submit_checker_policy_id,
setup_run_id,
)
await service.update_project_setup_run_status(
setup_run_id,
status="post_submit_policy_compiled",
current_step="post_submit_checker_policy_compilation",
output_post_submit_checker_policy_id=policy.id,
post_submit_derivation_summary=summary
| {"post_submit_checker_policy_id": policy.id},
continuation_effective_policy_id=effective_policy_id,
continuation_pre_submit_checker_policy_id=pre_submit_checker_policy_id,
)
return {
"status": "post_submit_policy_compiled",
"idempotent": False,
"post_submit_checker_policy_id": policy.id,
}
🤖 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/workers/project_setup.py` around lines 273 - 297, Normalize every
“post_submit_policy_compiled” return in the setup flow, including the
already_compiled branch and the success path in
run_post_submit_checker_policy_compilation, to include both
post_submit_checker_policy_id and idempotent. Obtain the existing policy ID for
already_compiled, use idempotent=True only for that branch and False for newly
compiled results, and ensure the race-recovery returns match the same shape.

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