a3bb78e06b
Security Quality Gate / npm audit, Bandit, pip-audit, detect-secrets (pull_request) Failing after 16m35s
5.6 KiB
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_idcolumns toreview_tasks,contract_search_documents, andapproval_timeline_items. - Added SQLAlchemy governance mixin and helper functions.
- Added default
deleted_at is nullfiltering 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_eventsremains 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:
contractscontract_filesreview_taskscontract_search_documentsapproval_timeline_itemsapproval_instancesapproval_stepsapproval_actionstemplate_lifecycle_eventslegal_asset_lifecycle_eventslegal_change_impact_scans
Tenant backfill tables:
review_taskscontract_search_documentsapproval_timeline_items
Compatibility Strategy
The migration is expand-only for runtime behavior:
- New governance fields are nullable.
tenant_idis added with a default for compatibility, then backfilled fromcontractswhere 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:18100healthy - Contract Web:
http://192.168.3.90:13000healthy - AI Platform API:
http://192.168.3.90:18101healthy - 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_atwithout direct DB updates. - Do not use
-ResetSmokeVolumesfor subsequent smoke upgrades unless the explicit goal is to rebuild the smoke database from scratch.