Files
ai-contract-platform/project-docs/V2-phase3-governance-soft-delete-implementation-2026-06-30.md
T
yuqei a3bb78e06b
Security Quality Gate / npm audit, Bandit, pip-audit, detect-secrets (pull_request) Failing after 16m35s
release: freeze V2 release candidate
2026-07-12 15:32:24 +08:00

5.6 KiB

AI Contract Platform V2 Phase 3 Slice 3.3 Governance And Soft Delete Implementation

Date: 2026-06-30

Scope

This slice implements the first governance and soft-delete migration for Contract API, following project-docs/V2-phase3-schema-hardening-design-review-2026-06-30.md.

Completed:

  • Added Alembic migration 20260630_0021_add_governance_soft_delete_fields.py.
  • Added governance columns to core business tables: created_by, updated_by, deleted_at.
  • Added missing tenant_id columns to review_tasks, contract_search_documents, and approval_timeline_items.
  • Added SQLAlchemy governance mixin and helper functions.
  • Added default deleted_at is null filtering for main read and write paths.
  • Added source-visibility filtering for unified search, so stale search documents do not expose soft-deleted contracts, files, or review tasks.
  • Added runtime schema check for governance columns.
  • Added regression tests for governance field writes and soft-delete visibility.

Not included in this slice:

  • No public delete or restore API was added.
  • contract_audit_events remains immutable and is not soft-deleted.
  • No cleanup migration removes old fields.
  • No Phase 3 review-result structured tables were added.
  • No UI field derivation changes were made.

Tables Covered

Governed tables:

  • contracts
  • contract_files
  • review_tasks
  • contract_search_documents
  • approval_timeline_items
  • approval_instances
  • approval_steps
  • approval_actions
  • template_lifecycle_events
  • legal_asset_lifecycle_events
  • legal_change_impact_scans

Tenant backfill tables:

  • review_tasks
  • contract_search_documents
  • approval_timeline_items

Compatibility Strategy

The migration is expand-only for runtime behavior:

  • New governance fields are nullable.
  • tenant_id is added with a default for compatibility, then backfilled from contracts where possible.
  • Existing API paths and response shapes are unchanged.
  • Repository/orchestration code now filters soft-deleted rows by default.
  • Search checks both search document visibility and source object visibility.

Runtime Behavior

Default hidden after deleted_at is set:

  • Contract list and detail.
  • Workspace summaries and pending tasks.
  • Contract files list/detail/preview/download.
  • Review task list, queue, claim, complete, fail paths.
  • Unified search results for contract, file, and review sources.
  • Template lifecycle event reads.
  • Legal asset lifecycle event reads.
  • Legal change impact scan history reads.

Still intentionally retained:

  • Audit facts remain readable through audit integrity paths because they are immutable evidence.
  • Backups still serialize contract headers in the MVP backup implementation; backup semantics should be reviewed in a later retention/archive slice.

Validation

Passed locally:

python -m compileall -q yuqei-contract-platform/services/contract-api/src/yuqei_contract_api yuqei-contract-platform/services/contract-api/migrations
python -m pytest yuqei-contract-platform/services/contract-api/tests -q

Passed local Alembic migration cycle on a temporary SQLite database:

python -m alembic -c alembic.ini upgrade head
python -m alembic -c alembic.ini downgrade 20260630_0020
python -m alembic -c alembic.ini upgrade head

New focused regressions:

  • Governance fields are recorded for contract, file, review task, and timeline rows.
  • Soft-deleted contract/file/review task rows are hidden from default read paths.
  • Runtime schema check reports governance_columns.

Next Step

Authoritative V2 smoke PostgreSQL/Docker verification passed on 192.168.3.90.

Deploy command:

$env:SSHPASS='<remote-root-password>'
powershell.exe -NoProfile -ExecutionPolicy Bypass -File yuqei-infra\scripts\deploy-v2-smoke-docker.ps1 -UseSshpass -AllowDirtyWorktree -KeepRemoteBackup -SkipSmoke

Deploy result:

  • Artifact: project-docs/qa-artifacts/v2-smoke-docker-deploy/2026-06-30T13-48-10
  • Script result: V2_SMOKE_DOCKER_DEPLOY_PASS
  • Compose project: yuqei-contract-v2-smoke
  • Contract API: http://192.168.3.90:18100 healthy
  • Contract Web: http://192.168.3.90:13000 healthy
  • AI Platform API: http://192.168.3.90:18101 healthy
  • AI golden sample gate: passed, 90 samples / 6 suites / 16 checks

Runtime schema check:

status=ok
database=yuqei_contract
alembic actual=20260630_0021
alembic expected_head=20260630_0021
core_tables checked_count=20
governance_columns checked_tables=11
governance_columns checked_columns=36
postgres_extensions=pg_trgm

DB and API smoke sampling:

tenant=smoke-governance-0021
contract_id=contract-ba1f38fd8889
file_id=file-7f0fa0003f7d
review_id=review-0f4356dc06d8
files_total=2
review_tasks=1
workspace_tasks=3
search_total=6

contract created_by=Smoke Owner updated_by=Smoke Legal not_deleted=true
file created_by=Smoke Uploader updated_by=Smoke Uploader not_deleted=true
review_task created_by=Smoke Legal updated_by=contract-review-worker-smoke-1 not_deleted=true

Soft-delete visibility smoke sampling:

contract_id=contract-e7e688407798
file_id=file-17b71b117566
review_id=review-087c10767e0f
detail_status_after_contract_soft_delete=404
files_total_after_file_soft_delete=0
review_tasks_after_soft_delete=0
search_total_after_contract_soft_delete=0

Next step after Slice 3.3:

  • Continue Phase 3 with Slice 3.4 UI display field derivation design, or first add a small product-level delete/restore API design if business operations need to exercise deleted_at without direct DB updates.
  • Do not use -ResetSmokeVolumes for subsequent smoke upgrades unless the explicit goal is to rebuild the smoke database from scratch.