# V2 Phase 3 AI Platform Request Tenant Context Date: 2026-07-02 ## Status Completed and smoke verified on `192.168.3.90`. This slice closes the request-level tenant boundary for the AI Platform high-frequency data paths: 1. Knowledge documents, chunks, import batches, reindex executions, and ingestion jobs. 2. AI Trace list/detail/update paths. 3. Quality improvement action create/list/detail/update paths. The API now accepts `X-Tenant-Id` and uses it as the request tenant context. If the header is omitted or blank, the system continues to use the backward-compatible `default` tenant. ## Implementation Added: - `yuqei_ai_platform_api.tenant_context` - Request middleware in `yuqei_ai_platform_api.main` - Tenant-aware SQLAlchemy filtering for knowledge, audit, and quality persistence - Tenant-aware in-memory repository behavior for tests and demo mode Important behavior: - New tenant-scoped rows are written with the current request tenant. - Read paths filter by the current request tenant. - AI Trace detail returns `404` when accessed from a different tenant. - Existing callers without `X-Tenant-Id` continue to read/write the `default` tenant. The legal, audit, and knowledge route handlers are async so the request tenant context is preserved across FastAPI execution. ## Smoke Verification Smoke environment: - Contract Web: `http://192.168.3.90:13000` - Contract API: `http://192.168.3.90:18100` - AI Platform API: `http://192.168.3.90:18101` Runtime checks: ```text GET http://192.168.3.90:18100/api/v1/runtime/schema-check -> ok GET http://192.168.3.90:18101/api/v1/runtime/schema-check -> ok ``` AI Platform schema-check result: ```json { "status": "ok", "alembic": { "actual": "20260702_0020", "expected_head": "20260702_0020" }, "tenant_columns": "ok", "trace_governance_columns": "ok", "secret_ref_columns": "ok", "pgvector_schema": "ok" } ``` Tenant smoke result: ```json { "status": "pass", "tenant_a": "tenant-smoke-20260702231614-a", "tenant_b": "tenant-smoke-20260702231614-b", "knowledge_search": { "tenant_a_count": 1, "tenant_b_count": 0 }, "ai_runs": { "tenant_a_run_tenant": "tenant-smoke-20260702231614-a", "tenant_b_run_tenant": "tenant-smoke-20260702231614-b", "cross_tenant_detail_status": 404 }, "quality_actions": { "created_tenant": "tenant-smoke-20260702231614-a", "tenant_b_visible_count": 0 } } ``` Verified endpoints: - `POST /api/v1/knowledge-documents` - `GET /api/v1/knowledge-documents/search` - `POST /api/v1/legal/qa` - `GET /api/v1/audit/ai-runs` - `GET /api/v1/audit/ai-runs/{run_id}` - `POST /api/v1/audit/quality-improvement-actions` - `GET /api/v1/audit/quality-improvement-actions` ## Deployment Note During verification, the prior smoke deployment had `contract-api` exited with code `139`. Direct `python -X faulthandler` import and uvicorn startup with `.env.smoke` did not reproduce the crash. Restarting the existing smoke services with the same `.env.smoke` recovered the stack and all services became healthy. Diagnostic note: remote compose commands for this smoke stack must include: ```bash docker compose -p yuqei-contract-v2-smoke --env-file .env.smoke -f docker-compose.yml ... ``` Running ad-hoc compose commands without `.env.smoke` can use local defaults that do not match the existing smoke Postgres volume. ## Local Validation Previously passed locally: ```powershell python -m pytest yuqei-ai-platform\services\ai-platform-api\tests\test_platform_data.py::test_request_tenant_context_isolates_knowledge_traces_and_quality_actions -q python -m pytest yuqei-ai-platform\services\ai-platform-api\tests -q ``` Result: - AI Platform API tests: 56 passed. ## Remaining Items Still pending for the broader AI Platform governance track: - Later tenant-aware auth/permission enforcement. - Later row-level security design, if required for production isolation. Recommended next slice: - Continue later hardening for scheduled Trace governance worker loops and policy-specific redaction rules. Trace governance worker implementation is recorded in: - `project-docs/V2-phase3-ai-platform-trace-governance-worker-2026-07-02.md`