test/integration/api/channels/test_account_router.py:55: in test_admin_can_list_accounts assert "items" in payload["data"] E AssertionError: assert 'items' in {'accounts': []}test/integration/api/channels/test_analytics_router.py:213: in test_admin_can_analyze_content_review assert response.status_code == 200, response.text E AssertionError: {"success":false,"error":{"code":"DEPENDENCY","message":"Dependency content_review_repository failed","trace_id":"5d6327ac537b4b18a27697a1ccd92042","details":{"cause":{"error_code":"ERROR","message":"(sqlalchemy.dialects.postgresql.asyncpg.ProgrammingError) <class 'asyncpg.exceptions.UndefinedFunctionError'>: function json_array_elements_text(jsonb) does not exist\nHINT: No function matches the given name and argument types. You might need to add explicit type casts.\n[SQL: SELECT json_array_elements_text(channel_content_review_records.categories) AS category, count(channel_content_review_records.id) AS count \nFROM channel_content_review_records \nWHERE channel_content_review_records.reviewed_at >= $1::TIMESTAMP WITHOUT TIME ZONE AND channel_content_review_records.reviewed_at < $2::TIMESTAMP WITHOUT TIME ZONE AND channel_content_review_records.is_deleted = $3::INTEGER GROUP BY json_array_elements_text(channel_content_review_records.categories)]\n[parameters: (datetime.datetime(2026, 1, 1, 0, 0), datetime.datetime(2026, 7, 1, 0, 0), 0)]\n(Background on this error at: https://sqlalche.me/e/20/f405)","trace_id":""},"dep":"content_review_repository"}}} E assert 502 == 200 E + where 502 = <Response [502 Bad Gateway]>.status_codetest/integration/api/channels/test_audit_router.py:44: in test_admin_can_query_audit_logs assert response.status_code == 200, response.text E AssertionError: {"success":false,"error":{"code":"DEPENDENCY","message":"Dependency audit_log failed","trace_id":"31e4478671814002893457c6b2aea5bb","details":{"cause":{"error_code":"ERROR","message":"invalid enum value for AuditOperationType: 'whitelist_batch_added'","trace_id":""},"dep":"audit_log"}}} E assert 502 == 200 E + where 502 = <Response [502 Bad Gateway]>.status_codetest/integration/api/channels/test_audit_router.py:128: in test_admin_can_export_audit_logs assert response.status_code == 200, response.text E AssertionError: {"success":false,"error":{"code":"DEPENDENCY","message":"Dependency audit_log failed","trace_id":"b2d12135439842b3a1830e7ebd4e58d3","details":{"cause":{"error_code":"ERROR","message":"invalid enum value for AuditOperationType: 'whitelist_batch_added'","trace_id":""},"dep":"audit_log"}}} E assert 502 == 200 E + where 502 = <Response [502 Bad Gateway]>.status_codetest/integration/api/channels/test_audit_router.py:195: in test_superadmin_can_update_retention_policy assert response.status_code == 200, response.text E AssertionError: {"success":false,"error":{"code":"INTERNAL","message":"control execution failed: This transaction is closed","trace_id":"5ea315ff6ce445a3ab4e9ec1b3e294c8","details":{"cause":{"type":"ResourceClosedError","message":"This transaction is closed"}}}} E assert 500 == 200 E + where 500 = <Response [500 Internal Server Error]>.status_codetest/integration/api/channels/test_config_router.py:125: in test_superadmin_can_import_config_dry_run assert response.status_code == 200, response.text E AssertionError: {"success":false,"error":{"code":"INTERNAL","message":"control execution failed: This transaction is closed","trace_id":"d41a318f32a24e70a2c36a7cd8a185ae","details":{"cause":{"type":"ResourceClosedError","message":"This transaction is closed"}}}} E assert 500 == 200 E + where 500 = <Response [500 Internal Server Error]>.status_codetest/integration/api/channels/test_config_router.py:194: in test_get_config_returns_404_for_non_existent_key assert response.status_code == 404, response.text E AssertionError: {"success":true,"data":{"key":"nonexistent_config_key_0000","value":"new_value","version":3,"scope":"global"}} E assert 200 == 404 E + where 200 = <Response [200 OK]>.status_codetest/integration/api/channels/test_config_router.py:212: in test_update_config_returns_404_for_non_existent_key assert response.status_code == 404, response.text E AssertionError: {"success":false,"error":{"code":"INTERNAL","message":"control execution failed: This transaction is closed","trace_id":"11abde4d53354420bcb61e3edbea7059","details":{"cause":{"type":"ResourceClosedError","message":"This transaction is closed"}}}} E assert 500 == 404 E + where 500 = <Response [500 Internal Server Error]>.status_codetest/integration/api/channels/test_config_router.py:230: in test_rollback_config_returns_404_for_non_existent_key assert response.status_code == 404, response.text E AssertionError: {"success":false,"error":{"code":"INTERNAL","message":"control execution failed: This transaction is closed","trace_id":"dec0d28af30046f8bd501429aae361f9","details":{"cause":{"type":"ResourceClosedError","message":"This transaction is closed"}}}} E assert 500 == 404 E + where 500 = <Response [500 Internal Server Error]>.status_codetest/integration/api/channels/test_config_router.py:259: in test_get_config_history_returns_404_for_non_existent_key assert response.status_code == 404, response.text E AssertionError: {"success":true,"data":{"key":"nonexistent_config_key_0000","history":[{"version":4,"value":"new_value","updated_at":"2026-07-03T14:50:17.571806"},{"version":3,"value":"new_value","updated_at":"2026-07-03T14:25:40.143051"},{"version":2,"value":"new_value","updated_at":"2026-07-03T14:25:40.068399"},{"version":1,"value":"new_value","updated_at":"2026-07-03T13:10:24.965318"}]}} E assert 200 == 404 E + where 200 = <Response [200 OK]>.status_codetest/integration/api/channels/test_content_review_router.py:72: in test_admin_preview_returns_404_or_400_for_non_existent_account assert response.status_code in (400, 404, 501), response.text E AssertionError: {"success":false,"error":{"code":"DEPENDENCY","message":"Dependency content_review_repository failed","trace_id":"0f5e5301e1064b6889d0e41f61e45831","details":{"cause":{"error_code":"ERROR","message":"(sqlalchemy.dialects.postgresql.asyncpg.Error) <class 'asyncpg.exceptions.InFailedSQLTransactionError'>: current transaction is aborted, commands ignored until end of transaction block\n[SQL: INSERT INTO channel_content_review_records (review_id, channel_type, account_id, resource_type, content_preview, verdict, confidence, categories, detail, reviewed_at, reviewer, source, trace_id, created_by, updated_by, created_at, updated_at, is_deleted, deleted_at) VALUES ($1::VARCHAR, $2::VARCHAR, $3::VARCHAR, $4::VARCHAR, $5::VARCHAR, $6::VARCHAR, $7::FLOAT, $8::JSONB, $9::JSONB, $10::TIMESTAMP WITHOUT TIME ZONE, $11::VARCHAR, $12::VARCHAR, $13::VARCHAR, $14::VARCHAR, $15::VARCHAR, $16::TIMESTAMP WITHOUT TIME ZONE, $17::TIMESTAMP WITHOUT TIME ZONE, $18::INTEGER, $19::TIMESTAMP WITHOUT TIME ZONE) RETURNING channel_content_review_records.id]\n[parameters: ('rev_20260703145018028377_c9d62a81', 'feishu', 'nonexistent_account_00000000', 'message_text', 'pytest content for review', 'pass', 0.95, '[]', '[]', datetime.datetime(2026, 7, 3, 14, 50, 18, 28421, tzinfo=datetime.timezone.utc), 'Kris', 'manual_preview', '0f5e5301e1064b6889d0e41f61e45831', None, None, datetime.datetime(2026, 7, 3, 14, 50, 18, 29714), datetime.datetime(2026, 7, 3, 14, 50, 18, 29718), 0, None)]\n(Background on this error at: https://sqlalche.me/e/20/dbapi)","trace_id":""},"dep":"content_review_repository"}}} E assert 502 in (400, 404, 501) E + where 502 = <Response [502 Bad Gateway]>.status_codetest/integration/api/channels/test_content_review_router.py:130: in test_admin_can_list_review_history assert response.status_code == 200, response.text E AssertionError: {"success":false,"error":{"code":"DEPENDENCY","message":"Dependency content_review_repository failed","trace_id":"abd5da7e9a3a4264b9bf1aee8d9fd19e","details":{"cause":{"error_code":"ERROR","message":"This Session's transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback(). Original exception was: (sqlalchemy.dialects.postgresql.asyncpg.Error) <class 'asyncpg.exceptions.InFailedSQLTransactionError'>: current transaction is aborted, commands ignored until end of transaction block\n[SQL: INSERT INTO channel_content_review_records (review_id, channel_type, account_id, resource_type, content_preview, verdict, confidence, categories, detail, reviewed_at, reviewer, source, trace_id, created_by, updated_by, created_at, updated_at, is_deleted, deleted_at) VALUES ($1::VARCHAR, $2::VARCHAR, $3::VARCHAR, $4::VARCHAR, $5::VARCHAR, $6::VARCHAR, $7::FLOAT, $8::JSONB, $9::JSONB, $10::TIMESTAMP WITHOUT TIME ZONE, $11::VARCHAR, $12::VARCHAR, $13::VARCHAR, $14::VARCHAR, $15::VARCHAR, $16::TIMESTAMP WITHOUT TIME ZONE, $17::TIMESTAMP WITHOUT TIME ZONE, $18::INTEGER, $19::TIMESTAMP WITHOUT TIME ZONE) RETURNING channel_content_review_records.id]\n[parameters: ('rev_20260703145018028377_c9d62a81', 'feishu', 'nonexistent_account_00000000', 'message_text', 'pytest content for review', 'pass', 0.95, '[]', '[]', datetime.datetime(2026, 7, 3, 14, 50, 18, 28421, tzinfo=datetime.timezone.utc), 'Kris', 'manual_preview', '0f5e5301e1064b6889d0e41f61e45831', None, None, datetime.datetime(2026, 7, 3, 14, 50, 18, 29714), datetime.datetime(2026, 7, 3, 14, 50, 18, 29718), 0, None)]\n(Background on this error at: https://sqlalche.me/e/20/dbapi) (Background on this error at: https://sqlalche.me/e/20/7s2a)","trace_id":""},"dep":"content_review_repository"}}} E assert 502 == 200 E + where 502 = <Response [502 Bad Gateway]>.status_codetest/integration/api/channels/test_content_review_router.py:192: in test_admin_can_get_review_stats assert response.status_code == 200, response.text E AssertionError: {"success":false,"error":{"code":"DEPENDENCY","message":"Dependency content_review_repository failed","trace_id":"f15a099f337c41689d788ea1cae3371e","details":{"cause":{"error_code":"ERROR","message":"This Session's transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback(). Original exception was: (sqlalchemy.dialects.postgresql.asyncpg.Error) <class 'asyncpg.exceptions.InFailedSQLTransactionError'>: current transaction is aborted, commands ignored until end of transaction block\n[SQL: INSERT INTO channel_content_review_records (review_id, channel_type, account_id, resource_type, content_preview, verdict, confidence, categories, detail, reviewed_at, reviewer, source, trace_id, created_by, updated_by, created_at, updated_at, is_deleted, deleted_at) VALUES ($1::VARCHAR, $2::VARCHAR, $3::VARCHAR, $4::VARCHAR, $5::VARCHAR, $6::VARCHAR, $7::FLOAT, $8::JSONB, $9::JSONB, $10::TIMESTAMP WITHOUT TIME ZONE, $11::VARCHAR, $12::VARCHAR, $13::VARCHAR, $14::VARCHAR, $15::VARCHAR, $16::TIMESTAMP WITHOUT TIME ZONE, $17::TIMESTAMP WITHOUT TIME ZONE, $18::INTEGER, $19::TIMESTAMP WITHOUT TIME ZONE) RETURNING channel_content_review_records.id]\n[parameters: ('rev_20260703145018028377_c9d62a81', 'feishu', 'nonexistent_account_00000000', 'message_text', 'pytest content for review', 'pass', 0.95, '[]', '[]', datetime.datetime(2026, 7, 3, 14, 50, 18, 28421, tzinfo=datetime.timezone.utc), 'Kris', 'manual_preview', '0f5e5301e1064b6889d0e41f61e45831', None, None, datetime.datetime(2026, 7, 3, 14, 50, 18, 29714), datetime.datetime(2026, 7, 3, 14, 50, 18, 29718), 0, None)]\n(Background on this error at: https://sqlalche.me/e/20/dbapi) (Background on this error at: https://sqlalche.me/e/20/7s2a)","trace_id":""},"dep":"content_review_repository"}}} E assert 502 == 200 E + where 502 = <Response [502 Bad Gateway]>.status_codetest/integration/api/channels/test_content_review_router.py:277: in test_get_review_returns_404_for_non_existent assert response.status_code == 404, response.text E AssertionError: {"success":false,"error":{"code":"DEPENDENCY","message":"Dependency content_review_repository failed","trace_id":"b600a7c10709451a91efdf1eb960353d","details":{"cause":{"error_code":"ERROR","message":"This Session's transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback(). Original exception was: (sqlalchemy.dialects.postgresql.asyncpg.Error) <class 'asyncpg.exceptions.InFailedSQLTransactionError'>: current transaction is aborted, commands ignored until end of transaction block\n[SQL: INSERT INTO channel_content_review_records (review_id, channel_type, account_id, resource_type, content_preview, verdict, confidence, categories, detail, reviewed_at, reviewer, source, trace_id, created_by, updated_by, created_at, updated_at, is_deleted, deleted_at) VALUES ($1::VARCHAR, $2::VARCHAR, $3::VARCHAR, $4::VARCHAR, $5::VARCHAR, $6::VARCHAR, $7::FLOAT, $8::JSONB, $9::JSONB, $10::TIMESTAMP WITHOUT TIME ZONE, $11::VARCHAR, $12::VARCHAR, $13::VARCHAR, $14::VARCHAR, $15::VARCHAR, $16::TIMESTAMP WITHOUT TIME ZONE, $17::TIMESTAMP WITHOUT TIME ZONE, $18::INTEGER, $19::TIMESTAMP WITHOUT TIME ZONE) RETURNING channel_content_review_records.id]\n[parameters: ('rev_20260703145018028377_c9d62a81', 'feishu', 'nonexistent_account_00000000', 'message_text', 'pytest content for review', 'pass', 0.95, '[]', '[]', datetime.datetime(2026, 7, 3, 14, 50, 18, 28421, tzinfo=datetime.timezone.utc), 'Kris', 'manual_preview', '0f5e5301e1064b6889d0e41f61e45831', None, None, datetime.datetime(2026, 7, 3, 14, 50, 18, 29714), datetime.datetime(2026, 7, 3, 14, 50, 18, 29718), 0, None)]\n(Background on this error at: https://sqlalche.me/e/20/dbapi) (Background on this error at: https://sqlalche.me/e/20/7s2a)","trace_id":""},"dep":"content_review_repository"}}} E assert 502 == 404 E + where 502 = <Response [502 Bad Gateway]>.status_codetest/integration/api/channels/test_content_review_router.py:295: in test_stats_path_not_captured_by_review_id assert response.status_code == 200, response.text E AssertionError: {"success":false,"error":{"code":"DEPENDENCY","message":"Dependency content_review_repository failed","trace_id":"45a169b8b00148bdb658e137ce4d38c0","details":{"cause":{"error_code":"ERROR","message":"This Session's transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback(). Original exception was: (sqlalchemy.dialects.postgresql.asyncpg.Error) <class 'asyncpg.exceptions.InFailedSQLTransactionError'>: current transaction is aborted, commands ignored until end of transaction block\n[SQL: INSERT INTO channel_content_review_records (review_id, channel_type, account_id, resource_type, content_preview, verdict, confidence, categories, detail, reviewed_at, reviewer, source, trace_id, created_by, updated_by, created_at, updated_at, is_deleted, deleted_at) VALUES ($1::VARCHAR, $2::VARCHAR, $3::VARCHAR, $4::VARCHAR, $5::VARCHAR, $6::VARCHAR, $7::FLOAT, $8::JSONB, $9::JSONB, $10::TIMESTAMP WITHOUT TIME ZONE, $11::VARCHAR, $12::VARCHAR, $13::VARCHAR, $14::VARCHAR, $15::VARCHAR, $16::TIMESTAMP WITHOUT TIME ZONE, $17::TIMESTAMP WITHOUT TIME ZONE, $18::INTEGER, $19::TIMESTAMP WITHOUT TIME ZONE) RETURNING channel_content_review_records.id]\n[parameters: ('rev_20260703145018028377_c9d62a81', 'feishu', 'nonexistent_account_00000000', 'message_text', 'pytest content for review', 'pass', 0.95, '[]', '[]', datetime.datetime(2026, 7, 3, 14, 50, 18, 28421, tzinfo=datetime.timezone.utc), 'Kris', 'manual_preview', '0f5e5301e1064b6889d0e41f61e45831', None, None, datetime.datetime(2026, 7, 3, 14, 50, 18, 29714), datetime.datetime(2026, 7, 3, 14, 50, 18, 29718), 0, None)]\n(Background on this error at: https://sqlalche.me/e/20/dbapi) (Background on this error at: https://sqlalche.me/e/20/7s2a)","trace_id":""},"dep":"content_review_repository"}}} E assert 502 == 200 E + where 502 = <Response [502 Bad Gateway]>.status_codetest/integration/api/channels/test_health_router.py:142: in test_admin_can_export_diagnostics_with_empty_body assert response.status_code == 200, response.text E AssertionError: {"success":false,"error":{"code":"INTERNAL","message":"diagnostics export failed: [DEPENDENCY] Dependency channel_audit_log failed","trace_id":"cba79be9bfb5486e92ee57950344db6a","details":{"cause":{"error_code":"ERROR","message":"[DEPENDENCY] Dependency channel_audit_log failed","trace_id":""}}}} E assert 500 == 200 E + where 500 = <Response [500 Internal Server Error]>.status_codetest/integration/api/channels/test_login_router.py:83: in test_qr_start_non_existent_account_returns_404 assert response.status_code == 404, response.text E AssertionError: {"success":false,"error":{"code":"DEPENDENCY","message":"Dependency feishu_api failed","trace_id":"9e60d09deb6f42bc8bd197003673f55b","details":{"cause":{"error_code":"NOT_FOUND","message":"config not found: app_id","trace_id":"","resource":"config","id":"app_id"},"dep":"feishu_api"}}} E assert 502 == 404 E + where 502 = <Response [502 Bad Gateway]>.status_codetest/integration/api/channels/test_message_router.py:293: in test_send_admin_message_with_non_existent_account_returns_404_or_400 assert response.status_code in (400, 404), response.text E AssertionError: {"success":false,"data":{"message_ids":[],"failures":[{"target":"nonexistent_target","error_code":"VALIDATION_ERROR","message":"invalid channel_type in target: nonexistent_target","retryable":false,"details":null}],"skipped":[]}} E assert 200 in (400, 404) E + where 200 = <Response [200 OK]>.status_codetest/integration/api/channels/test_outbox_router.py:191: in test_admin_can_batch_retry_dead_letter assert response.status_code == 200, response.text E AssertionError: {"success":false,"error":{"code":"INTERNAL","message":"control execution failed: This transaction is closed","trace_id":"6dba06f439d64b69969467f6df9e565b","details":{"cause":{"type":"ResourceClosedError","message":"This transaction is closed"}}}} E assert 500 == 200 E + where 500 = <Response [500 Internal Server Error]>.status_codetest/integration/api/channels/test_reports_router.py:64: in test_admin_can_create_oneoff_report assert response.status_code == 200, response.text E AssertionError: {"success":false,"error":{"code":"INTERNAL","message":"control execution failed: This transaction is closed","trace_id":"dfa5be90a4a047159d77f20c1c610a45","details":{"cause":{"type":"ResourceClosedError","message":"This transaction is closed"}}}} E assert 500 == 200 E + where 500 = <Response [500 Internal Server Error]>.status_codetest/integration/api/channels/test_webhook_router.py:29: in test_webhook_does_not_require_auth assert response.status_code in (200, 500, 501), response.text E AssertionError: {"success":false,"error":{"code":"NOT_FOUND","message":"channel_account not found: feishu:<webhook>","trace_id":"e595066ec3884a8cab1bde4f0228f8cd","details":{"resource":"channel_account","id":"feishu:<webhook>"}}} E assert 404 in (200, 500, 501) E + where 404 = <Response [404 Not Found]>.status_codetest/integration/api/channels/test_webhook_router.py:76: in test_verify_signature_does_not_require_auth assert response.status_code in (200, 501), response.text E AssertionError: {"success":false,"error":{"code":"NOT_FOUND","message":"config not found: encrypt_key","trace_id":"1d60b3be44404678bca3adb5248ef019","details":{"resource":"config","id":"encrypt_key"}}} E assert 404 in (200, 501) E + where 404 = <Response [404 Not Found]>.status_codetest/integration/api/channels/test_webhook_router.py:93: in test_verify_signature_with_valid_body_returns_200_or_501 assert response.status_code in (200, 501), response.text E AssertionError: {"success":false,"error":{"code":"NOT_FOUND","message":"config not found: encrypt_key","trace_id":"1bf8262d0d55470cba16de5b62e2ea6c","details":{"resource":"config","id":"encrypt_key"}}} E assert 404 in (200, 501) E + where 404 = <Response [404 Not Found]>.status_codetest/integration/api/channels/test_wizard_router.py:178: in test_oauth_initiate_rejects_invalid_redirect_uri_scheme assert response.status_code == 422, response.text E AssertionError: {"success":false,"error":{"code":"INTERNAL","message":"Internal server error","trace_id":null,"details":{}}} E assert 500 == 422 E + where 500 = <Response [500 Internal Server Error]>.status_codetest/integration/api/channels/test_wizard_router.py:258: in test_oauth_callback_rejects_invalid_redirect_uri_scheme assert response.status_code == 422, response.text E AssertionError: {"success":false,"error":{"code":"INTERNAL","message":"Internal server error","trace_id":null,"details":{}}} E assert 500 == 422 E + where 500 = <Response [500 Internal Server Error]>.status_code