# V2 Phase 3 Slice C: Legacy Action Column Cleanup Date: 2026-07-02 ## Scope Slice C removes the legacy persisted UI action cache columns from `contracts`: - `contracts.next_action` - `contracts.next_actions` The API response fields remain compatible. `next_action` and `next_actions` are still returned by serializers, but they are derived from `ContractActionContext` and `derive_contract_display(...)` instead of stored database columns. `contracts.action_hint` remains the supported manual action hint field. ## Implementation - Added Alembic revision `20260702_0025_drop_legacy_contract_action_columns`. - `upgrade()` drops `next_action` and `next_actions` from `contracts`. - `downgrade()` restores both columns with safe defaults for rollback to the previous schema. - Removed the legacy columns from `ContractModel`. - Removed legacy action cache values from `ContractCreateData` and SQLAlchemy contract creation. - Kept domain/API response DTOs unchanged. - Updated runtime schema-check: - required status cache columns remain `status_label,status_tone`; - old action columns still present are reported as `removable_compat_fields`; - old action columns removed are reported as `removed_compat_fields`; - missing status cache columns still produce an error. ## Verification Local checks passed: - `python -m py_compile` for changed Contract API modules and the new migration. - `python -m pytest yuqei-contract-platform\services\contract-api\tests\test_health.py -q` - `python -m pytest yuqei-contract-platform\services\contract-api\tests\test_display_cache_governance.py -q` - targeted contract workflow tests for action hint, deprecated alias rejection, search document action context, and derived action display. Alembic was verified on a temporary local SQLite database: - `upgrade head` reached `20260702_0025`. - `contracts.next_action` and `contracts.next_actions` were absent after upgrade. - `downgrade 20260701_0024` restored both legacy columns. ## Smoke Status Remote smoke on `192.168.3.90` passed. Environment: - Remote path: `/opt/apps/ai-contract-platform-v2-smoke` - Compose project: `yuqei-contract-v2-smoke` - Contract API: `http://192.168.3.90:18100` - Contract Web: `http://192.168.3.90:13000` - Database: `yuqei_contract` - Deploy artifact: `project-docs/qa-artifacts/v2-smoke-docker-deploy/2026-07-02T10-56-23` Deploy: - Standard smoke deploy script passed with `-UseSshpass -AllowDirtyWorktree -KeepRemoteBackup -SkipSmoke`. - Core containers were running and healthy: PostgreSQL, Redis, MinIO, Contract API, Contract Web, AI Platform API, worker, and contract-review-worker. - AI golden sample asset gate passed: `90` samples, `6` suites, `16` checks. Migration and schema-check: - `contract_api_alembic_version=20260702_0025`. - `contracts.next_action` and `contracts.next_actions` are absent in PostgreSQL. - `/api/v1/runtime/schema-check` overall status: `ok`. - `alembic_version`: `ok`, actual and expected head both `20260702_0025`. - `display_cache_consistency`: `ok`, checked rows `12025`, mismatch count `0`. - `display_cache_cleanup_prestate`: `ok`, `legacy_action_columns_removed=true`, `removed_compat_fields=next_action,next_actions`, `next_step=legacy_action_column_cleanup_complete`. API smoke sample: - Created smoke contract: `contract-ce86ce621a83`. - Contract detail still returns derived `next_action` and `next_actions`. - `PATCH action_hint=ACTION-HINT-SMOKE-20260702` succeeded and response `next_action` was derived from `action_hint`. - Legacy `PATCH next_action=...` returned `422` with `deprecated_contract_update_action_alias`. - Contract list returned the derived `next_action`. - Unified search matched the contract and indexed the derived action hint in the snippet. Log and metrics: - Deprecated alias metrics recorded the intentional rejected legacy PATCH for `contract-ce86ce621a83`. - No recent Contract API `ERROR`, traceback, exception, or `Contract display cache mismatch` log entries were found after the smoke checks.