# V2 Phase 3 Review Result Write Path Policy Date: 2026-07-01 ## Background Phase 3 has introduced structured review result tables: - `review_risk_items` - `review_citations` - `review_repair_actions` Read paths are being moved to structured-first behavior while keeping the public `ReviewTask.risk_items` and `ReviewTask.citations` response fields compatible. The current write path still dual-writes legacy JSON and structured rows: 1. `review_worker.execute_review_task(...)` converts AI Platform review output into JSON-compatible `risk_items`, `citations`, and `primary_sources`. 2. `SqlAlchemyReviewOrchestration.complete_review_task(...)` enriches `risk_items` with legal asset recommendations such as `clause_recommendations`. 3. `ContractReviewTaskRepository.complete_review_task(...)` writes `review_tasks.risk_items`, `review_tasks.citations`, `primary_sources`, `confidence`, and `ai_audit_run_id`. 4. `sync_structured_review_results(...)` rebuilds `review_risk_items` and `review_citations` from the persisted review task payload. 5. Clause repair writes structured repair state and still updates legacy `risk_items` when legacy JSON exists. ## Decision Do not stop writing legacy `review_tasks.risk_items` or `review_tasks.citations` yet. For the current Phase 3 slice, these JSON columns are compatibility/display caches, not the primary source for structured queries or state decisions when structured rows exist. ## Field Policy | Field | Current role | Policy | | --- | --- | --- | | `review_tasks.risk_items` | Compatibility display cache. Still carries rich UI payload such as `clause_recommendations`, original AI fields, `related_clause`, and legacy repair display fields. | Continue dual-write. Do not treat as primary read source when structured rows exist. | | `review_tasks.citations` | Compatibility display cache. Can carry metadata not yet modeled in `review_citations`, such as `source_type`, `score`, `locator`, `document_id`, `chunk_id`, and `knowledge_base_id`. | Continue dual-write. Structured citations remain primary for query/search; legacy-only citations stay supplemental. | | `review_tasks.primary_sources` | AI source payload cache. Not covered by the structured risk/citation migration. | Continue write. Revisit in a later source/provenance slice. | | `review_tasks.risk_level` | Aggregate task-level risk. | Continue write. | | `review_risk_items` | Structured risk rows for queries, action context, repair state, and structured read APIs. | Primary source for structured behavior. | | `review_citations` | Structured citation rows for query/search and structured read APIs. | Primary source for structured citation behavior. | | `review_repair_actions` | Structured repair action history. | Primary source for repair audit/state. | ## Freeze Preconditions Before freezing or stopping writes to `review_tasks.risk_items`, V2 needs one of: - structured storage for full clause recommendation cards, or - a serializer that can regenerate compatible `clause_recommendations` from published clause/rule snapshots, repair actions, and structured risk rows. Before freezing or stopping writes to `review_tasks.citations`, V2 needs one of: - structured metadata on `review_citations`, or - a serializer that can regenerate compatibility fields such as `source_type`, `score`, `locator`, `document_id`, `chunk_id`, and `knowledge_base_id`. ## Guardrails - Keep API responses compatible: `ReviewTask.risk_items` and `ReviewTask.citations` remain present. - New read/query/search behavior should use structured rows first. - Legacy JSON may supplement structured rows where it contains compatibility-only fields. - No column removal or stop-write migration should be done until the freeze preconditions are met and verified in smoke. ## Completed Follow-Up Slice The first structured recommendation slice is complete: - `review_risk_recommendations` now stores recommendation cards structurally. - `StructuredReviewRisk.clause_recommendations` is available to management/read pages. - `ReviewTask.risk_items` can synthesize `clause_recommendations` from structured recommendations when legacy risk JSON is absent. Legacy `review_tasks.risk_items` is still written as a compatibility display cache. It should not be frozen until smoke backfill verifies recommendation coverage on existing review tasks. ## Status Update As of this slice, the legacy JSON fields remain writable and are intentionally treated as compatibility display caches. Structured rows are already the primary source for query/search/repair logic, but the JSON payload is still needed for front-end compatibility until recommendation cards and citation metadata are fully modeled structurally.