add changes#27
Conversation
📝 WalkthroughWalkthroughThe PR updates agent HITL interruption handling, adds structured schema-planning models, enforces fully qualified table uniqueness, expands API contracts, and refactors the agent testing page around validated form state and typed resume payloads. ChangesAgent workflow updates
Table identity enforcement
API contracts and agent testing UI
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant AgentTestingPage
participant AgentRouter
participant chat_with_agent
participant agent_graph
AgentTestingPage->>AgentRouter: submit configuration or resume value
AgentRouter->>chat_with_agent: forward tool arguments
chat_with_agent->>agent_graph: inspect saved interrupt state
chat_with_agent->>agent_graph: resume or update state
agent_graph-->>chat_with_agent: final state or interruption
chat_with_agent-->>AgentRouter: return result and interrupt details
Possibly related PRs
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
agent/src/agent/nodes/schema_explorer.py (1)
611-617: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winPopulate the
errorfield when structured output parsing fails.The
errorfield was recently added toSchemaExplorerOutput, but it is not being populated in the fallback object when an exception is caught. Including the exception details here prevents the error from being silently swallowed downstream.🐛 Proposed fix
except Exception as e: print(f"Structured output parsing failed in schema explorer: {e}") data = SchemaExplorerOutput( schema_plan=None, ambiguity_detected=False, ambiguity_message="", candidate_options=[], + error=str(e), )🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@agent/src/agent/nodes/schema_explorer.py` around lines 611 - 617, Update the SchemaExplorerOutput fallback construction in the exception handler to populate its error field with the caught exception details, while preserving the existing default values for schema_plan, ambiguity_detected, ambiguity_message, and candidate_options.backend/app/routers/tables.py (1)
223-224: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick winRace condition on concurrent table creation.
There is a Time-of-Check to Time-of-Use (TOCTOU) race condition between the
selectcheck above and thiscommit. If two identical creation requests execute concurrently, both will pass theselectcheck. The second request'scommitwill then violate the new database-levelUniqueConstraintand throw an unhandledIntegrityError, resulting in a 500 Internal Server Error crash instead of the intended 409 Conflict.Catch the
IntegrityErrorto safely fall back to the 409 Conflict response.🔒️ Proposed fix to handle concurrency gracefully
+ from sqlalchemy.exc import IntegrityError + session.add(table) - session.commit() + try: + session.commit() + except IntegrityError: + session.rollback() + raise HTTPException( + status_code=409, + detail=f"Table '{catalog_name}.{schema_name}.{name}' already exists." + )🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/app/routers/tables.py` around lines 223 - 224, Update the table-creation flow around session.add(table) and session.commit() to catch the database IntegrityError caused by concurrent duplicate inserts, roll back the session, and return the existing 409 Conflict response instead of propagating a 500 error. Preserve the current pre-insert select check and successful commit behavior.frontend/src/pages/AgentTestingPage.tsx (1)
1372-1381: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
isResumingis alwaysfalsewhen this renders, and the 300ms delay leaves a double-submission window.The parent only mounts this branch when
chatResponse && !chatMutation.isPending(unchanged, line 1373), but is then givenisResuming={chatMutation.isPending}(line 1378) — which is therefore alwaysfalsefor the lifetime of this mount. Combined withhandleApprove/handleReject(lines 1123-1145) callingchatMutation.mutate()inside an un-guardedsetTimeout(..., 300), the Approve/Reject buttons inAgentApprovalForm(lines 590-598,disabled/loading={isResuming}) never actually disable during that 300ms window, so a fast double-click can queue twomutate()calls resuming the samethread_id— a non-idempotent external call to the agent.Tracking submission state locally (set synchronously on click, independent of
chatMutation.isPending) would close this window, e.g.:🔒️ Illustrative fix (needs matching change to the outer render-guard too)
+ const [isSubmittingResume, setIsSubmittingResume] = useState(false); + const handleApprove = (resumeValue?: ResumeValue) => { if (!threadId) return; const config = watch(); + setIsSubmittingResume(true); setTimeout(() => { chatMutation.mutate({ thread_id: threadId, resume_value: resumeValue !== undefined ? resumeValue : { approved: true }, hitl_enabled: config.hitlEnabled, - }); + }, { onSettled: () => setIsSubmittingResume(false) }); }, 300); };Then pass
isResuming={isSubmittingResume}at line 1378 instead ofchatMutation.isPending.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/src/pages/AgentTestingPage.tsx` around lines 1372 - 1381, Track resume submission locally in the AgentTestingPage approval flow, setting the state synchronously when handleApprove or handleReject is triggered and preventing subsequent submissions until completion. Update the AnimatePresence render guard and the AgentApprovalForm isResuming prop to use this local isSubmittingResume state, so the form remains mounted while submitting and its buttons disable immediately through the delayed chatMutation call.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@agent/src/agent/nodes/schema_explorer.py`:
- Around line 172-175: Update the error field definition to use default=None
instead of default_factory=str, preserving its Optional[str] type and existing
description.
In `@backend/app/routers/agent.py`:
- Around line 70-79: Update the TraceSpan construction and its response model
handling so a missing Langfuse observation name/type never produces a None
span_name or response validation failure. Provide a non-null fallback label when
both values are absent, preserving the existing name/type preference and
ensuring all entries returned by the trace endpoint satisfy TraceSpan.span_name:
str.
In `@frontend/openapi.json`:
- Line 1: Confirm that the intentional migration of all endpoints to the /api
prefix has no consumers outside the generated TypeScript client; if external
consumers exist, preserve legacy routes or add a documented deprecation window
before removing them. Track the separate OpenAPI hygiene findings for global
security declarations and maxItems constraints on array schemas, without
expanding this prefix-migration change unless required.
- Line 1: The OpenAPI snapshot and generated frontend types are stale.
Regenerate the spec and frontend types from the current backend models so
`/api/agent/traces/{trace_id}` references the proper `TraceSpan` response schema
and `QueryApproval` contains only `approved` and `feedback`, removing
`rejection_category` and `suggested_fix`.
In `@frontend/src/components/tables/TableList.tsx`:
- Around line 86-91: Update duplicate validation around isDuplicate in TableList
to read the complete fetched table collection from the global query cache rather
than the filtered data variable. Mirror the cache-access pattern used by
OnboardingWizard, then preserve the existing oasis_source_id and composite-name
comparisons against all cached tables.
In `@frontend/src/pages/AgentTestingPage.tsx`:
- Around line 39-64: Replace the hand-written object variant in ResumeValue with
the existing QueryApproval type exported from ../api/agent, while preserving the
string and empty-record variants. Update the import in AgentTestingPage.tsx to
include QueryApproval and derive ResumeValue from that schema type so future
QueryApproval changes remain reflected automatically.
- Around line 1105-1120: The chat mutation setup in the AgentTestingPage
currently applies tableMode only to allowed_statuses while always forwarding
allowedTables. Wire tableMode into the ChatRequest so Exclusive mode excludes
the selected tables, or explicitly rename/reposition the control if it is
intended to govern statuses only; also simplify the redundant allowed_statuses
empty-length expression while preserving the request’s expected empty-array
behavior.
---
Outside diff comments:
In `@agent/src/agent/nodes/schema_explorer.py`:
- Around line 611-617: Update the SchemaExplorerOutput fallback construction in
the exception handler to populate its error field with the caught exception
details, while preserving the existing default values for schema_plan,
ambiguity_detected, ambiguity_message, and candidate_options.
In `@backend/app/routers/tables.py`:
- Around line 223-224: Update the table-creation flow around session.add(table)
and session.commit() to catch the database IntegrityError caused by concurrent
duplicate inserts, roll back the session, and return the existing 409 Conflict
response instead of propagating a 500 error. Preserve the current pre-insert
select check and successful commit behavior.
In `@frontend/src/pages/AgentTestingPage.tsx`:
- Around line 1372-1381: Track resume submission locally in the AgentTestingPage
approval flow, setting the state synchronously when handleApprove or
handleReject is triggered and preventing subsequent submissions until
completion. Update the AnimatePresence render guard and the AgentApprovalForm
isResuming prop to use this local isSubmittingResume state, so the form remains
mounted while submitting and its buttons disable immediately through the delayed
chatMutation call.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: e384fa67-0f2d-4f66-b8db-0dfa0ee21015
📒 Files selected for processing (16)
agent/src/agent/mcp_server.pyagent/src/agent/nodes/query_builder.pyagent/src/agent/nodes/refiner.pyagent/src/agent/nodes/satisfaction_check.pyagent/src/agent/nodes/schema_explorer.pybackend/alembic/versions/70e8a34ff877_add_unique_constraint_to_tables.pybackend/app/config.pybackend/app/routers/agent.pybackend/app/routers/tables.pycore/src/core/models/models.pyfrontend/openapi.jsonfrontend/src/api/agent.tsfrontend/src/api/schema.d.tsfrontend/src/components/tables/TableList.tsxfrontend/src/components/wizard/OnboardingWizard.tsxfrontend/src/pages/AgentTestingPage.tsx
| error: Optional[str] = Field( | ||
| default_factory=str, | ||
| description="Error message if any" | ||
| ) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
Set default to None for optional fields.
Since error is typed as Optional[str], using default_factory=str initializes it to an empty string "" instead of None. It is more idiomatic and semantically accurate to use default=None for optional error fields.
♻️ Proposed refactor
error: Optional[str] = Field(
- default_factory=str,
+ default=None,
description="Error message if any"
)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| error: Optional[str] = Field( | |
| default_factory=str, | |
| description="Error message if any" | |
| ) | |
| error: Optional[str] = Field( | |
| default=None, | |
| description="Error message if any" | |
| ) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@agent/src/agent/nodes/schema_explorer.py` around lines 172 - 175, Update the
error field definition to use default=None instead of default_factory=str,
preserving its Optional[str] type and existing description.
| class TraceSpan(BaseModel): | ||
| span_name: str | ||
| start_time: str | None = None | ||
| duration_ms: int = 0 | ||
| input_tokens: int = 0 | ||
| output_tokens: int = 0 | ||
| model: str = "N/A" | ||
| status: str | ||
| input_preview: str = "" | ||
| output_preview: str = "" |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
span_name can be None from Langfuse data, but the model requires str — one bad observation 500s the whole endpoint.
obs.get("name") or obs.get("type") returns None if both are missing/falsy, but TraceSpan.span_name: str has no default and isn't Optional. Since the endpoint uses response_model=list[TraceSpan], FastAPI will raise a ResponseValidationError (500) when serializing the response if any observation hits this case, breaking the trace timeline for the whole trace instead of just skipping/labeling that one span.
🛡️ Proposed fix
timeline.append(
{
- "span_name": obs.get("name") or obs.get("type"),
+ "span_name": obs.get("name") or obs.get("type") or "unknown",Also applies to: 304-316
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@backend/app/routers/agent.py` around lines 70 - 79, Update the TraceSpan
construction and its response model handling so a missing Langfuse observation
name/type never produces a None span_name or response validation failure.
Provide a non-null fallback label when both values are absent, preserving the
existing name/type preference and ensuring all entries returned by the trace
endpoint satisfy TraceSpan.span_name: str.
| } | ||
| } | ||
| } | ||
| {"openapi": "3.1.0", "info": {"title": "Text2SQL Studio API", "description": "Data Intelligence module \u2014 Evaluation Orchestration & Monitoring", "version": "2.0.0"}, "paths": {"/api/tables/{table_id}/health": {"get": {"tags": ["health"], "summary": "Get Table Health", "operationId": "get_table_health_api_tables__table_id__health_get", "parameters": [{"name": "table_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Table Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TableHealthRead"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/tables/{table_id}/health/recompute": {"post": {"tags": ["health"], "summary": "Recompute Health", "operationId": "recompute_health_api_tables__table_id__health_recompute_post", "parameters": [{"name": "table_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Table Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TableHealthRead"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/health/all": {"get": {"tags": ["health"], "summary": "Get All Health", "description": "Returns the latest health record for every table (used in the table list view).", "operationId": "get_all_health_api_health_all_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/TableHealthRead"}, "type": "array", "title": "Response Get All Health Api Health All Get"}}}}}}}, "/api/health/esca": {"get": {"tags": ["health"], "summary": "Get Esca Health", "operationId": "get_esca_health_api_health_esca_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}}}, "/api/admin/login": {"post": {"tags": ["admin_auth"], "summary": "Login", "description": "Validate that the supplied email belongs to an active admin in security.users.\nReturns the user record on success; raises 403 when the user is not an admin.", "operationId": "login_api_admin_login_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/LoginRequest"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SecurityUserRead"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/admin/tables/pending": {"get": {"tags": ["admin_approval"], "summary": "Get Pending Tables", "description": "Get all tables in 'verified' status (awaiting admin approval).", "operationId": "get_pending_tables_api_admin_tables_pending_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"type": "object"}, "type": "array", "title": "Response Get Pending Tables Api Admin Tables Pending Get"}}}}}}}, "/api/admin/tables/{table_id}/approve": {"post": {"tags": ["admin_approval"], "summary": "Approve Table", "description": "Approve a verified table for production.\n\nActions:\n 1. Set table.status = production\n 2. Sync its golden questions to the shared 'text2sql_production' Langfuse dataset", "operationId": "approve_table_api_admin_tables__table_id__approve_post", "parameters": [{"name": "table_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Table Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/admin/tables/{table_id}/reject": {"post": {"tags": ["admin_approval"], "summary": "Reject Table", "description": "Reject a verified table, returning it to sandbox.", "operationId": "reject_table_api_admin_tables__table_id__reject_post", "parameters": [{"name": "table_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Table Id"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/RejectionNote"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/agent/chat": {"post": {"tags": ["agent"], "summary": "Chat", "description": "Start a new agent session or resume an interrupted one.\n\n- First call: provide `query` (and optionally `allowed_tables`, `allowed_statuses`, `extractors`).\n- Resume call: provide `thread_id` + `resume_value` (`{\"approved\": true}` or\n `{\"approved\": false, \"feedback\": \"...\"}`).\n\nThe backend forwards the request to the agent MCP service and returns the\nstructured result. The frontend only deals with this endpoint.", "operationId": "chat_api_agent_chat_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/ChatRequest"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ChatResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/agent/stream/{thread_id}": {"get": {"tags": ["agent"], "summary": "Stream Agent Execution", "description": "Subscribe to Redis PubSub for agent graph execution events and yield them as SSE.", "operationId": "stream_agent_execution_api_agent_stream__thread_id__get", "parameters": [{"name": "thread_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Thread Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/agent/traces/{trace_id}": {"get": {"tags": ["agent"], "summary": "Get Trace Timeline", "description": "Fetch trace from Langfuse and normalize observations for frontend timeline.", "operationId": "get_trace_timeline_api_agent_traces__trace_id__get", "parameters": [{"name": "trace_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Trace Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/agent/suggest_fixes": {"post": {"tags": ["agent"], "summary": "Suggest Fixes", "description": "Generate quick fixes during HITL interruption via MCP.", "operationId": "suggest_fixes_api_agent_suggest_fixes_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/SuggestFixesRequest"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/auth/login/{provider}": {"get": {"tags": ["auth"], "summary": "Login", "operationId": "login_api_v1_auth_login__provider__get", "parameters": [{"name": "provider", "in": "path", "required": true, "schema": {"type": "string", "title": "Provider"}}, {"name": "next_url", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Next Url"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/auth/callback/{provider}": {"get": {"tags": ["auth"], "summary": "Auth Callback", "operationId": "auth_callback_api_v1_auth_callback__provider__get", "parameters": [{"name": "provider", "in": "path", "required": true, "schema": {"type": "string", "title": "Provider"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/auth/logout": {"get": {"tags": ["auth"], "summary": "Logout", "operationId": "logout_api_v1_auth_logout_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}}}, "/api/v1/auth/config": {"get": {"tags": ["auth"], "summary": "Get Auth Config", "operationId": "get_auth_config_api_v1_auth_config_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AuthConfigRead"}}}}}}}, "/api/v1/auth/me": {"get": {"tags": ["auth"], "summary": "Get Me", "operationId": "get_me_api_v1_auth_me_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SecurityUserRead"}}}}}}}, "/api/tables": {"get": {"tags": ["tables"], "summary": "List Tables", "operationId": "list_tables_api_tables_get", "parameters": [{"name": "status", "in": "query", "required": false, "schema": {"anyOf": [{"$ref": "#/components/schemas/TableStatus"}, {"type": "null"}], "title": "Status"}}, {"name": "owner_id", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Owner Id"}}, {"name": "search", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Search"}}, {"name": "x-scope-id", "in": "header", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "X-Scope-Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "array", "items": {"$ref": "#/components/schemas/TableRead"}, "title": "Response List Tables Api Tables Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "post": {"tags": ["tables"], "summary": "Create Table", "operationId": "create_table_api_tables_post", "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TableCreate"}}}}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TableRead"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/tables/{table_id}": {"get": {"tags": ["tables"], "summary": "Get Table", "operationId": "get_table_api_tables__table_id__get", "parameters": [{"name": "table_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Table Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TableRead"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/tables/{table_id}/sync-schema": {"post": {"tags": ["tables"], "summary": "Sync Table Schema", "operationId": "sync_table_schema_api_tables__table_id__sync_schema_post", "parameters": [{"name": "table_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Table Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TableRead"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/tables/{table_id}/status": {"patch": {"tags": ["tables"], "summary": "Update Table Status", "description": "Update a table's status.", "operationId": "update_table_status_api_tables__table_id__status_patch", "parameters": [{"name": "table_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Table Id"}}, {"name": "status", "in": "query", "required": true, "schema": {"$ref": "#/components/schemas/TableStatus"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TableRead"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/tables/{table_id}/foreign-keys": {"get": {"tags": ["tables"], "summary": "Get Foreign Keys", "description": "Get all custom foreign key mappings for a table.", "operationId": "get_foreign_keys_api_tables__table_id__foreign_keys_get", "parameters": [{"name": "table_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Table Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "array", "items": {"$ref": "#/components/schemas/ForeignKeyMappingRead"}, "title": "Response Get Foreign Keys Api Tables Table Id Foreign Keys Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "post": {"tags": ["tables"], "summary": "Create Foreign Key", "description": "Create or update a foreign key mapping for a specific column in the table.", "operationId": "create_foreign_key_api_tables__table_id__foreign_keys_post", "parameters": [{"name": "table_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Table Id"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ForeignKeyMappingCreate"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ForeignKeyMappingRead"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/tables/{table_id}/foreign-keys/{fk_id}": {"delete": {"tags": ["tables"], "summary": "Delete Foreign Key", "description": "Delete a specific foreign key mapping.", "operationId": "delete_foreign_key_api_tables__table_id__foreign_keys__fk_id__delete", "parameters": [{"name": "table_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Table Id"}}, {"name": "fk_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Fk Id"}}], "responses": {"204": {"description": "Successful Response"}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/tables/{table_id}/enrichment": {"post": {"tags": ["enrichment"], "summary": "Create Enrichment", "description": "Save a new enrichment version for a table.\n\nIf the table is currently in 'production' and the new enrichment\nchanges the table_description or schema fields, the table is\nautomatically moved to 'degraded'.\n\nThis forces a full re-evaluation cycle before the table can be\npromoted to production again.", "operationId": "create_enrichment_api_tables__table_id__enrichment_post", "parameters": [{"name": "table_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Table Id"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EnrichmentCreate"}}}}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EnrichmentRead"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/tables/{table_id}/enrichment/latest": {"get": {"tags": ["enrichment"], "summary": "Get Latest Enrichment", "operationId": "get_latest_enrichment_api_tables__table_id__enrichment_latest_get", "parameters": [{"name": "table_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Table Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EnrichmentRead"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/tables/{table_id}/questions": {"get": {"tags": ["golden-questions"], "summary": "List Questions", "operationId": "list_questions_api_tables__table_id__questions_get", "parameters": [{"name": "table_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Table Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "array", "items": {"$ref": "#/components/schemas/GoldenQuestionRead"}, "title": "Response List Questions Api Tables Table Id Questions Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "post": {"tags": ["golden-questions"], "summary": "Create Question", "operationId": "create_question_api_tables__table_id__questions_post", "parameters": [{"name": "table_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Table Id"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GoldenQuestionCreate"}}}}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GoldenQuestionRead"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/tables/{table_id}/questions/upload": {"post": {"tags": ["golden-questions"], "summary": "Upload Questions", "operationId": "upload_questions_api_tables__table_id__questions_upload_post", "parameters": [{"name": "table_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Table Id"}}], "requestBody": {"required": true, "content": {"multipart/form-data": {"schema": {"$ref": "#/components/schemas/Body_upload_questions_api_tables__table_id__questions_upload_post"}}}}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/tables/{table_id}/questions/{question_id}": {"delete": {"tags": ["golden-questions"], "summary": "Delete Question", "operationId": "delete_question_api_tables__table_id__questions__question_id__delete", "parameters": [{"name": "table_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Table Id"}}, {"name": "question_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Question Id"}}], "responses": {"204": {"description": "Successful Response"}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/eval/readiness": {"get": {"tags": ["evaluation"], "summary": "Get Readiness", "operationId": "get_readiness_api_eval_readiness_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}}}, "/api/tables/{table_id}/eval/run": {"post": {"tags": ["evaluation"], "summary": "Trigger Eval", "operationId": "trigger_eval_api_tables__table_id__eval_run_post", "parameters": [{"name": "table_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Table Id"}}], "responses": {"202": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EvalRunRead"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/tables/{table_id}/eval/runs": {"get": {"tags": ["evaluation"], "summary": "List Runs", "operationId": "list_runs_api_tables__table_id__eval_runs_get", "parameters": [{"name": "table_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Table Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "array", "items": {"$ref": "#/components/schemas/EvalRunRead"}, "title": "Response List Runs Api Tables Table Id Eval Runs Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/eval/runs/all": {"get": {"tags": ["evaluation"], "summary": "Get All Eval Runs", "operationId": "get_all_eval_runs_api_eval_runs_all_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/EvalRunRead"}, "type": "array", "title": "Response Get All Eval Runs Api Eval Runs All Get"}}}}}}}, "/api/eval/batch/{promotion_run_id}": {"get": {"tags": ["evaluation"], "summary": "Get Batch Runs", "operationId": "get_batch_runs_api_eval_batch__promotion_run_id__get", "parameters": [{"name": "promotion_run_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Promotion Run Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "array", "items": {"$ref": "#/components/schemas/EvalRunRead"}, "title": "Response Get Batch Runs Api Eval Batch Promotion Run Id Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/eval/{run_id}": {"get": {"tags": ["evaluation"], "summary": "Get Run", "operationId": "get_run_api_eval__run_id__get", "parameters": [{"name": "run_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Run Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EvalRunRead"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/eval/{run_id}/results": {"get": {"tags": ["evaluation"], "summary": "Get Results", "operationId": "get_results_api_eval__run_id__results_get", "parameters": [{"name": "run_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Run Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "array", "items": {"$ref": "#/components/schemas/EvalResultRead"}, "title": "Response Get Results Api Eval Run Id Results Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/eval/{run_id}/report": {"get": {"tags": ["evaluation"], "summary": "Get Run Report", "operationId": "get_run_report_api_eval__run_id__report_get", "parameters": [{"name": "run_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Run Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/eval/{run_id}/regression-diff": {"get": {"tags": ["evaluation"], "summary": "Get Regression Diff", "description": "For a promotion-regression run, return questions that passed the baseline\nbut failed in the regression \u2014 true regressions introduced by the new candidate table.", "operationId": "get_regression_diff_api_eval__run_id__regression_diff_get", "parameters": [{"name": "run_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Run Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/extractors": {"get": {"tags": ["extractors"], "summary": "List Extractors", "description": "List all registered HTTP extractors.", "operationId": "list_extractors_api_extractors_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/HttpExtractorRead"}, "type": "array", "title": "Response List Extractors Api Extractors Get"}}}}}}, "post": {"tags": ["extractors"], "summary": "Create Extractor", "description": "Register a new HTTP extractor.", "operationId": "create_extractor_api_extractors_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/HttpExtractorCreate"}}}, "required": true}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HttpExtractorRead"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/extractors/{extractor_id}": {"delete": {"tags": ["extractors"], "summary": "Delete Extractor", "description": "Delete an HTTP extractor by ID.", "operationId": "delete_extractor_api_extractors__extractor_id__delete", "parameters": [{"name": "extractor_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Extractor Id"}}], "responses": {"204": {"description": "Successful Response"}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/evaluations/run": {"post": {"tags": ["evaluation-orchestration"], "summary": "Trigger Evaluation Run", "description": "Trigger evaluation for one or more tables.", "operationId": "trigger_evaluation_run_api_evaluations_run_post", "parameters": [{"name": "triggered_by", "in": "query", "required": false, "schema": {"type": "string", "default": "user", "title": "Triggered By"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "array", "items": {"type": "string"}, "title": "Table Ids"}}}}, "responses": {"202": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "array", "items": {"$ref": "#/components/schemas/EvalRunRead"}, "title": "Response Trigger Evaluation Run Api Evaluations Run Post"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/evaluations/runs": {"get": {"tags": ["evaluation-orchestration"], "summary": "List Runs", "operationId": "list_runs_api_evaluations_runs_get", "parameters": [{"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "maximum": 200, "default": 50, "title": "Limit"}}, {"name": "offset", "in": "query", "required": false, "schema": {"type": "integer", "default": 0, "title": "Offset"}}, {"name": "status", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Status"}}, {"name": "table_id", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Table Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "array", "items": {"$ref": "#/components/schemas/EvalRunRead"}, "title": "Response List Runs Api Evaluations Runs Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/evaluations/runs/{run_id}": {"get": {"tags": ["evaluation-orchestration"], "summary": "Get Run", "operationId": "get_run_api_evaluations_runs__run_id__get", "parameters": [{"name": "run_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Run Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EvalRunRead"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/evaluations/runs/{run_id}/report": {"get": {"tags": ["evaluation-orchestration"], "summary": "Get Run Report", "description": "Full structured report \u2014 matches the evaluation_pipeline.md format.", "operationId": "get_run_report_api_evaluations_runs__run_id__report_get", "parameters": [{"name": "run_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Run Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/evaluations/schedules": {"get": {"tags": ["evaluation-orchestration"], "summary": "List Schedules", "operationId": "list_schedules_api_evaluations_schedules_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/EvaluationScheduleRead"}, "type": "array", "title": "Response List Schedules Api Evaluations Schedules Get"}}}}}}, "post": {"tags": ["evaluation-orchestration"], "summary": "Create Schedule", "operationId": "create_schedule_api_evaluations_schedules_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/EvaluationScheduleCreate"}}}, "required": true}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EvaluationScheduleRead"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/evaluations/schedules/{schedule_id}": {"put": {"tags": ["evaluation-orchestration"], "summary": "Update Schedule", "operationId": "update_schedule_api_evaluations_schedules__schedule_id__put", "parameters": [{"name": "schedule_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Schedule Id"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EvaluationScheduleUpdate"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EvaluationScheduleRead"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "delete": {"tags": ["evaluation-orchestration"], "summary": "Delete Schedule", "operationId": "delete_schedule_api_evaluations_schedules__schedule_id__delete", "parameters": [{"name": "schedule_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Schedule Id"}}], "responses": {"204": {"description": "Successful Response"}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/evaluations/analytics/trends": {"get": {"tags": ["evaluation-orchestration"], "summary": "Get Trends", "description": "Score and pass_rate over time. Returns one data point per completed run.", "operationId": "get_trends_api_evaluations_analytics_trends_get", "parameters": [{"name": "days", "in": "query", "required": false, "schema": {"type": "integer", "default": 30, "title": "Days"}}, {"name": "table_id", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Table Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/evaluations/analytics/tables": {"get": {"tags": ["evaluation-orchestration"], "summary": "Get Table Analytics", "description": "Per-table performance ranking.", "operationId": "get_table_analytics_api_evaluations_analytics_tables_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}}}, "/api/evaluations/compare": {"get": {"tags": ["evaluation-orchestration"], "summary": "Compare Runs", "description": "Side-by-side comparison of two eval runs.", "operationId": "compare_runs_api_evaluations_compare_get", "parameters": [{"name": "run1", "in": "query", "required": true, "schema": {"type": "string", "title": "Run1"}}, {"name": "run2", "in": "query", "required": true, "schema": {"type": "string", "title": "Run2"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/evaluations/alerts": {"get": {"tags": ["evaluation-orchestration"], "summary": "List Alerts", "operationId": "list_alerts_api_evaluations_alerts_get", "parameters": [{"name": "acknowledged", "in": "query", "required": false, "schema": {"anyOf": [{"type": "boolean"}, {"type": "null"}], "title": "Acknowledged"}}, {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "default": 50, "title": "Limit"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "array", "items": {"$ref": "#/components/schemas/EvaluationAlertRead"}, "title": "Response List Alerts Api Evaluations Alerts Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/evaluations/alerts/{alert_id}/acknowledge": {"post": {"tags": ["evaluation-orchestration"], "summary": "Acknowledge Alert", "operationId": "acknowledge_alert_api_evaluations_alerts__alert_id__acknowledge_post", "parameters": [{"name": "alert_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Alert Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EvaluationAlertRead"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/evaluations/system-health": {"get": {"tags": ["evaluation-orchestration"], "summary": "System Health", "description": "Aggregate system health for the control center dashboard.", "operationId": "system_health_api_evaluations_system_health_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}}}, "/api/tables/{table_id}/publish": {"post": {"tags": ["publish"], "summary": "Publish Table", "operationId": "publish_table_api_tables__table_id__publish_post", "parameters": [{"name": "table_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Table Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/scopes": {"get": {"tags": ["scopes"], "summary": "List Scopes", "operationId": "list_scopes_api_scopes_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/UserScopeRead"}, "type": "array", "title": "Response List Scopes Api Scopes Get"}}}}}}, "post": {"tags": ["scopes"], "summary": "Create Scope", "operationId": "create_scope_api_scopes_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserScopeCreate"}}}, "required": true}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserScopeRead"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/scopes/{scope_id}/activate": {"post": {"tags": ["scopes"], "summary": "Activate Scope", "operationId": "activate_scope_api_scopes__scope_id__activate_post", "parameters": [{"name": "scope_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Scope Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserScopeRead"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/audit/queries": {"get": {"tags": ["audit"], "summary": "List Audit Queries", "operationId": "list_audit_queries_api_audit_queries_get", "parameters": [{"name": "table_id", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Table Id"}}, {"name": "user_id", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "User Id"}}, {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "maximum": 200, "default": 50, "title": "Limit"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "array", "items": {"$ref": "#/components/schemas/AuditQueryRead"}, "title": "Response List Audit Queries Api Audit Queries Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/tables/{table_id}/profile": {"get": {"tags": ["profiling"], "summary": "Get Table Profile", "operationId": "get_table_profile_api_tables__table_id__profile_get", "parameters": [{"name": "table_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Table Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TableProfileRead"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/tables/all/profile/run": {"post": {"tags": ["profiling"], "summary": "Run All Profiles", "description": "Triggers profiling for all registered tables.\nIdeal for Airflow DAGs to keep profiles up-to-date.", "operationId": "run_all_profiles_api_tables_all_profile_run_post", "parameters": [{"name": "force", "in": "query", "required": false, "schema": {"type": "boolean", "default": false, "title": "Force"}}], "responses": {"202": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/tables/{table_id}/profile/run": {"post": {"tags": ["profiling"], "summary": "Run Table Profile", "description": "Trigger a new profiling run against Trino.\nReturns immediately (202) while profiling runs in the background.\nRespects a 24h cache unless force=True.", "operationId": "run_table_profile_api_tables__table_id__profile_run_post", "parameters": [{"name": "table_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Table Id"}}, {"name": "force", "in": "query", "required": false, "schema": {"type": "boolean", "default": false, "title": "Force"}}], "responses": {"202": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TableProfileRead"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/tables/{table_id}/profile/columns": {"get": {"tags": ["profiling"], "summary": "Get Column Profiles", "operationId": "get_column_profiles_api_tables__table_id__profile_columns_get", "parameters": [{"name": "table_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Table Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "array", "items": {"$ref": "#/components/schemas/ColumnProfileRead"}, "title": "Response Get Column Profiles Api Tables Table Id Profile Columns Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/tables/{table_id}/columns/{column}/profile": {"get": {"tags": ["profiling"], "summary": "Get Single Column Profile", "operationId": "get_single_column_profile_api_tables__table_id__columns__column__profile_get", "parameters": [{"name": "table_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Table Id"}}, {"name": "column", "in": "path", "required": true, "schema": {"type": "string", "title": "Column"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ColumnProfileRead"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/tables/{table_id}/profile/context": {"get": {"tags": ["profiling"], "summary": "Get Profile Context", "description": "Returns a compact, LLM-ready context blob built from the latest\ncompleted profile. Used by the TextToSQL context builder for\nsystem-prompt injection, enrichment suggestions, and join suggestions.", "operationId": "get_profile_context_api_tables__table_id__profile_context_get", "parameters": [{"name": "table_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Table Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "object", "title": "Response Get Profile Context Api Tables Table Id Profile Context Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/tables/{table_id}/cross-profile": {"post": {"tags": ["profiling"], "summary": "Cross Profile", "description": "Discover cross-table join suggestions based on profiling statistics.", "operationId": "cross_profile_api_tables__table_id__cross_profile_post", "parameters": [{"name": "table_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Table Id"}}], "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "array", "items": {"$ref": "#/components/schemas/CrossTableProfileRead"}, "title": "Response Cross Profile Api Tables Table Id Cross Profile Post"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "get": {"tags": ["profiling"], "summary": "Get Cross Profiles", "operationId": "get_cross_profiles_api_tables__table_id__cross_profile_get", "parameters": [{"name": "table_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Table Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "array", "items": {"$ref": "#/components/schemas/CrossTableProfileRead"}, "title": "Response Get Cross Profiles Api Tables Table Id Cross Profile Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/feedback": {"post": {"tags": ["feedback"], "summary": "Submit Feedback", "operationId": "submit_feedback_api_feedback_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/QueryFeedbackCreate"}}}, "required": true}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/QueryFeedbackRead"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/feedback/table/{table_id}": {"get": {"tags": ["feedback"], "summary": "Get Table Feedback", "operationId": "get_table_feedback_api_feedback_table__table_id__get", "parameters": [{"name": "table_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Table Id"}}, {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "default": 50, "title": "Limit"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "array", "items": {"$ref": "#/components/schemas/QueryFeedbackRead"}, "title": "Response Get Table Feedback Api Feedback Table Table Id Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/feedback/query/{query_id}": {"get": {"tags": ["feedback"], "summary": "Get Query Feedback", "operationId": "get_query_feedback_api_feedback_query__query_id__get", "parameters": [{"name": "query_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Query Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "array", "items": {"$ref": "#/components/schemas/QueryFeedbackRead"}, "title": "Response Get Query Feedback Api Feedback Query Query Id Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/health": {"get": {"summary": "Health Check", "operationId": "health_check_health_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}}}}, "components": {"schemas": {"AlertSeverity": {"type": "string", "enum": ["info", "warning", "critical"], "title": "AlertSeverity"}, "AuditQueryRead": {"properties": {"id": {"type": "string", "title": "Id"}, "table_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Table Id"}, "user_id": {"type": "string", "title": "User Id"}, "session_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Session Id"}, "raw_question": {"type": "string", "title": "Raw Question"}, "normalized_question": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Normalized Question"}, "tables_accessed": {"anyOf": [{"items": {"type": "string"}, "type": "array"}, {"type": "null"}], "title": "Tables Accessed"}, "final_sql": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Final Sql"}, "result_row_count": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Result Row Count"}, "result_columns": {"anyOf": [{"items": {"type": "string"}, "type": "array"}, {"type": "null"}], "title": "Result Columns"}, "execution_time_ms": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Execution Time Ms"}, "refiner_iterations": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Refiner Iterations"}, "status": {"type": "string", "title": "Status"}, "error_message": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Error Message"}, "langfuse_trace_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Langfuse Trace Id"}, "confidence_score": {"anyOf": [{"type": "number"}, {"type": "null"}], "title": "Confidence Score"}, "explanation_text": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Explanation Text"}, "warnings_json": {"anyOf": [{"items": {"type": "string"}, "type": "array"}, {"type": "null"}], "title": "Warnings Json"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}}, "type": "object", "required": ["id", "table_id", "user_id", "session_id", "raw_question", "normalized_question", "tables_accessed", "final_sql", "result_row_count", "result_columns", "execution_time_ms", "refiner_iterations", "status", "error_message", "langfuse_trace_id", "confidence_score", "explanation_text", "warnings_json", "created_at"], "title": "AuditQueryRead"}, "AuthConfigRead": {"properties": {"ENABLE_KEYCLOAK": {"type": "boolean", "title": "Enable Keycloak"}, "ENABLE_GOOGLE": {"type": "boolean", "title": "Enable Google"}}, "type": "object", "required": ["ENABLE_KEYCLOAK", "ENABLE_GOOGLE"], "title": "AuthConfigRead"}, "Body_upload_questions_api_tables__table_id__questions_upload_post": {"properties": {"file": {"type": "string", "format": "binary", "title": "File"}}, "type": "object", "required": ["file"], "title": "Body_upload_questions_api_tables__table_id__questions_upload_post"}, "ChatRequest": {"properties": {"query": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Query"}, "thread_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Thread Id"}, "resume_value": {"anyOf": [{"$ref": "#/components/schemas/QueryApproval"}, {"type": "string"}, {"type": "object"}, {"type": "null"}], "title": "Resume Value"}, "allowed_tables": {"anyOf": [{"items": {"type": "string"}, "type": "array"}, {"type": "null"}], "title": "Allowed Tables"}, "allowed_statuses": {"anyOf": [{"items": {"type": "string"}, "type": "array"}, {"type": "null"}], "title": "Allowed Statuses"}, "extractors": {"anyOf": [{"items": {"type": "string"}, "type": "array"}, {"type": "null"}], "title": "Extractors"}, "active_skills": {"anyOf": [{"items": {"type": "string"}, "type": "array"}, {"type": "null"}], "title": "Active Skills"}, "execution_mode": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Execution Mode"}, "hitl_enabled": {"type": "boolean", "title": "Hitl Enabled", "default": true}}, "type": "object", "title": "ChatRequest"}, "ChatResponse": {"properties": {"thread_id": {"type": "string", "title": "Thread Id"}, "status": {"type": "string", "title": "Status"}, "interrupt_details": {"anyOf": [{"type": "object"}, {"type": "null"}], "title": "Interrupt Details"}, "summary": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Summary"}, "raw_data_ref": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Raw Data Ref"}, "sql_query": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Sql Query"}, "sql_explanation": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Sql Explanation"}, "schema_plan": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Schema Plan"}, "trace_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Trace Id"}, "execution_path": {"anyOf": [{"items": {"type": "string"}, "type": "array"}, {"type": "null"}], "title": "Execution Path"}}, "type": "object", "required": ["thread_id", "status"], "title": "ChatResponse"}, "ColumnProfileRead": {"properties": {"id": {"type": "string", "title": "Id"}, "table_id": {"type": "string", "title": "Table Id"}, "profile_id": {"type": "string", "title": "Profile Id"}, "column_name": {"type": "string", "title": "Column Name"}, "data_type": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Data Type"}, "null_count": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Null Count"}, "null_rate": {"anyOf": [{"type": "number"}, {"type": "null"}], "title": "Null Rate"}, "distinct_count": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Distinct Count"}, "min_value": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Min Value"}, "max_value": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Max Value"}, "avg_value": {"anyOf": [{"type": "number"}, {"type": "null"}], "title": "Avg Value"}, "median_value": {"anyOf": [{"type": "number"}, {"type": "null"}], "title": "Median Value"}, "top_values": {"anyOf": [{}, {"type": "null"}], "title": "Top Values"}, "is_categorical": {"type": "boolean", "title": "Is Categorical"}, "is_geo": {"type": "boolean", "title": "Is Geo"}, "is_time": {"type": "boolean", "title": "Is Time"}, "semantic_type": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Semantic Type"}, "stats_json": {"anyOf": [{}, {"type": "null"}], "title": "Stats Json"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}}, "type": "object", "required": ["id", "table_id", "profile_id", "column_name", "data_type", "null_count", "null_rate", "distinct_count", "min_value", "max_value", "avg_value", "median_value", "top_values", "is_categorical", "is_geo", "is_time", "semantic_type", "stats_json", "created_at"], "title": "ColumnProfileRead"}, "CrossTableProfileRead": {"properties": {"id": {"type": "string", "title": "Id"}, "source_table_id": {"type": "string", "title": "Source Table Id"}, "target_table_id": {"type": "string", "title": "Target Table Id"}, "join_suggestion": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Join Suggestion"}, "match_strength": {"type": "string", "title": "Match Strength"}, "common_columns": {"anyOf": [{"items": {"type": "string"}, "type": "array"}, {"type": "null"}], "title": "Common Columns"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}}, "type": "object", "required": ["id", "source_table_id", "target_table_id", "join_suggestion", "match_strength", "common_columns", "created_at"], "title": "CrossTableProfileRead"}, "DifficultyLevel": {"type": "string", "enum": ["simple", "medium", "complex"], "title": "DifficultyLevel"}, "EnrichmentCreate": {"properties": {"data": {"type": "object", "title": "Data"}}, "type": "object", "required": ["data"], "title": "EnrichmentCreate"}, "EnrichmentRead": {"properties": {"id": {"type": "string", "title": "Id"}, "table_id": {"type": "string", "title": "Table Id"}, "version": {"type": "integer", "title": "Version"}, "data": {"anyOf": [{"type": "object"}, {"type": "null"}], "title": "Data"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}}, "type": "object", "required": ["id", "table_id", "version", "data", "created_at"], "title": "EnrichmentRead"}, "EvalResultRead": {"properties": {"id": {"type": "string", "title": "Id"}, "run_id": {"type": "string", "title": "Run Id"}, "question_id": {"type": "string", "title": "Question Id"}, "score": {"type": "number", "title": "Score"}, "status": {"type": "string", "title": "Status"}, "error_type": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Error Type"}}, "type": "object", "required": ["id", "run_id", "question_id", "score", "status", "error_type"], "title": "EvalResultRead"}, "EvalRunRead": {"properties": {"id": {"type": "string", "title": "Id"}, "table_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Table Id"}, "table_name": {"type": "string", "title": "Table Name"}, "dataset_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Dataset Id"}, "score": {"type": "number", "title": "Score"}, "pass_rate": {"type": "number", "title": "Pass Rate"}, "fail_rate": {"type": "number", "title": "Fail Rate"}, "total_questions": {"type": "integer", "title": "Total Questions"}, "duration_seconds": {"anyOf": [{"type": "number"}, {"type": "null"}], "title": "Duration Seconds"}, "triggered_by": {"type": "string", "title": "Triggered By"}, "status": {"$ref": "#/components/schemas/EvalStatus"}, "started_at": {"type": "string", "format": "date-time", "title": "Started At"}, "completed_at": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "Completed At"}, "failure_breakdown": {"anyOf": [{"type": "object"}, {"type": "null"}], "title": "Failure Breakdown"}, "dimension_averages": {"anyOf": [{"type": "object"}, {"type": "null"}], "title": "Dimension Averages"}, "regression_detected": {"type": "boolean", "title": "Regression Detected"}, "regression_delta": {"anyOf": [{"type": "number"}, {"type": "null"}], "title": "Regression Delta"}, "promotion_run_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Promotion Run Id"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}}, "type": "object", "required": ["id", "table_id", "table_name", "dataset_id", "score", "pass_rate", "fail_rate", "total_questions", "duration_seconds", "triggered_by", "status", "started_at", "completed_at", "failure_breakdown", "dimension_averages", "regression_detected", "regression_delta", "created_at"], "title": "EvalRunRead"}, "EvalStatus": {"type": "string", "enum": ["running", "completed", "failed"], "title": "EvalStatus"}, "EvaluationAlertRead": {"properties": {"id": {"type": "string", "title": "Id"}, "run_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Run Id"}, "table_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Table Id"}, "alert_type": {"type": "string", "title": "Alert Type"}, "severity": {"$ref": "#/components/schemas/AlertSeverity"}, "message": {"type": "string", "title": "Message"}, "details": {"anyOf": [{"type": "object"}, {"type": "null"}], "title": "Details"}, "acknowledged": {"type": "boolean", "title": "Acknowledged"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}}, "type": "object", "required": ["id", "run_id", "table_id", "alert_type", "severity", "message", "details", "acknowledged", "created_at"], "title": "EvaluationAlertRead"}, "EvaluationScheduleCreate": {"properties": {"dataset_id": {"type": "string", "title": "Dataset Id"}, "table_scope": {"anyOf": [{"items": {"type": "string"}, "type": "array"}, {"type": "null"}], "title": "Table Scope"}, "cron_expression": {"type": "string", "title": "Cron Expression", "default": "0 2 * * *"}, "enabled": {"type": "boolean", "title": "Enabled", "default": true}, "created_by": {"type": "string", "title": "Created By", "default": "user"}}, "type": "object", "required": ["dataset_id"], "title": "EvaluationScheduleCreate"}, "EvaluationScheduleRead": {"properties": {"id": {"type": "string", "title": "Id"}, "dataset_id": {"type": "string", "title": "Dataset Id"}, "table_scope": {"anyOf": [{"items": {"type": "string"}, "type": "array"}, {"type": "null"}], "title": "Table Scope"}, "cron_expression": {"type": "string", "title": "Cron Expression"}, "enabled": {"type": "boolean", "title": "Enabled"}, "created_by": {"type": "string", "title": "Created By"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "last_run_at": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "Last Run At"}, "next_run_at": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "Next Run At"}}, "type": "object", "required": ["id", "dataset_id", "table_scope", "cron_expression", "enabled", "created_by", "created_at", "last_run_at", "next_run_at"], "title": "EvaluationScheduleRead"}, "EvaluationScheduleUpdate": {"properties": {"dataset_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Dataset Id"}, "table_scope": {"anyOf": [{"items": {"type": "string"}, "type": "array"}, {"type": "null"}], "title": "Table Scope"}, "cron_expression": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Cron Expression"}, "enabled": {"anyOf": [{"type": "boolean"}, {"type": "null"}], "title": "Enabled"}}, "type": "object", "title": "EvaluationScheduleUpdate"}, "ExtractorStatus": {"type": "string", "enum": ["draft", "sandbox", "verified", "production", "degraded"], "title": "ExtractorStatus"}, "FeedbackRating": {"type": "string", "enum": ["positive", "negative"], "title": "FeedbackRating"}, "ForeignKeyMappingCreate": {"properties": {"source_column": {"type": "string", "title": "Source Column"}, "target_table_id": {"type": "string", "title": "Target Table Id"}, "target_column": {"type": "string", "title": "Target Column"}}, "type": "object", "required": ["source_column", "target_table_id", "target_column"], "title": "ForeignKeyMappingCreate"}, "ForeignKeyMappingRead": {"properties": {"id": {"type": "string", "title": "Id"}, "table_id": {"type": "string", "title": "Table Id"}, "source_column": {"type": "string", "title": "Source Column"}, "target_table_id": {"type": "string", "title": "Target Table Id"}, "target_column": {"type": "string", "title": "Target Column"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "updated_at": {"type": "string", "format": "date-time", "title": "Updated At"}}, "type": "object", "required": ["id", "table_id", "source_column", "target_table_id", "target_column", "created_at", "updated_at"], "title": "ForeignKeyMappingRead"}, "GoldenQuestionCreate": {"properties": {"question": {"type": "string", "title": "Question"}, "expected_sql": {"type": "string", "title": "Expected Sql"}, "difficulty": {"$ref": "#/components/schemas/DifficultyLevel", "default": "simple"}, "question_type": {"$ref": "#/components/schemas/QuestionType", "default": "simple"}, "coverage_tags": {"anyOf": [{"items": {"type": "string"}, "type": "array"}, {"type": "null"}], "title": "Coverage Tags"}}, "type": "object", "required": ["question", "expected_sql"], "title": "GoldenQuestionCreate"}, "GoldenQuestionRead": {"properties": {"id": {"type": "string", "title": "Id"}, "table_id": {"type": "string", "title": "Table Id"}, "question": {"type": "string", "title": "Question"}, "expected_sql": {"type": "string", "title": "Expected Sql"}, "difficulty": {"$ref": "#/components/schemas/DifficultyLevel"}, "question_type": {"$ref": "#/components/schemas/QuestionType"}, "coverage_tags": {"anyOf": [{"items": {"type": "string"}, "type": "array"}, {"type": "null"}], "title": "Coverage Tags"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}}, "type": "object", "required": ["id", "table_id", "question", "expected_sql", "difficulty", "question_type", "coverage_tags", "created_at"], "title": "GoldenQuestionRead"}, "HTTPValidationError": {"properties": {"detail": {"items": {"$ref": "#/components/schemas/ValidationError"}, "type": "array", "title": "Detail"}}, "type": "object", "title": "HTTPValidationError"}, "HealthStatus": {"type": "string", "enum": ["good", "warning", "critical"], "title": "HealthStatus"}, "HttpExtractorCreate": {"properties": {"name": {"type": "string", "title": "Name"}, "url": {"type": "string", "title": "Url"}, "description": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Description"}, "status": {"$ref": "#/components/schemas/ExtractorStatus", "default": "draft"}}, "type": "object", "required": ["name", "url"], "title": "HttpExtractorCreate"}, "HttpExtractorRead": {"properties": {"id": {"type": "string", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "url": {"type": "string", "title": "Url"}, "description": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Description"}, "status": {"$ref": "#/components/schemas/ExtractorStatus"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "updated_at": {"type": "string", "format": "date-time", "title": "Updated At"}}, "type": "object", "required": ["id", "name", "url", "description", "status", "created_at", "updated_at"], "title": "HttpExtractorRead"}, "LoginRequest": {"properties": {"email": {"type": "string", "title": "Email"}}, "type": "object", "required": ["email"], "title": "LoginRequest"}, "ProfilingStatus": {"type": "string", "enum": ["pending", "running", "completed", "failed"], "title": "ProfilingStatus"}, "QueryApproval": {"properties": {"approved": {"type": "boolean", "title": "Approved"}, "feedback": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Feedback"}, "rejection_category": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Rejection Category"}, "suggested_fix": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Suggested Fix"}}, "type": "object", "required": ["approved"], "title": "QueryApproval"}, "QueryFeedbackCreate": {"properties": {"user_id": {"type": "string", "title": "User Id"}, "query_id": {"type": "string", "title": "Query Id"}, "table_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Table Id"}, "rating": {"$ref": "#/components/schemas/FeedbackRating"}, "comment": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Comment"}, "suggested_correction": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Suggested Correction"}}, "type": "object", "required": ["user_id", "query_id", "rating"], "title": "QueryFeedbackCreate"}, "QueryFeedbackRead": {"properties": {"id": {"type": "string", "title": "Id"}, "user_id": {"type": "string", "title": "User Id"}, "query_id": {"type": "string", "title": "Query Id"}, "table_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Table Id"}, "rating": {"$ref": "#/components/schemas/FeedbackRating"}, "comment": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Comment"}, "suggested_correction": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Suggested Correction"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}}, "type": "object", "required": ["id", "user_id", "query_id", "table_id", "rating", "comment", "suggested_correction", "created_at"], "title": "QueryFeedbackRead"}, "QuestionType": {"type": "string", "enum": ["simple", "complex", "join", "geo", "aggregate", "time_series"], "title": "QuestionType"}, "RejectionNote": {"properties": {"note": {"type": "string", "title": "Note"}}, "type": "object", "required": ["note"], "title": "RejectionNote"}, "SecurityUserRead": {"properties": {"id": {"type": "string", "title": "Id"}, "email": {"type": "string", "title": "Email"}, "name": {"type": "string", "title": "Name"}, "is_active": {"type": "boolean", "title": "Is Active"}, "is_admin": {"type": "boolean", "title": "Is Admin"}, "provider": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Provider"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "updated_at": {"type": "string", "format": "date-time", "title": "Updated At"}}, "type": "object", "required": ["id", "email", "name", "is_active", "is_admin", "provider", "created_at", "updated_at"], "title": "SecurityUserRead"}, "SuggestFixesRequest": {"properties": {"thread_id": {"type": "string", "title": "Thread Id"}, "category": {"type": "string", "title": "Category"}}, "type": "object", "required": ["thread_id", "category"], "title": "SuggestFixesRequest"}, "TableCreate": {"properties": {"oasis_source_id": {"type": "string", "title": "Oasis Source Id"}}, "type": "object", "required": ["oasis_source_id"], "title": "TableCreate"}, "TableHealthRead": {"properties": {"id": {"type": "string", "title": "Id"}, "table_id": {"type": "string", "title": "Table Id"}, "health_score": {"type": "number", "title": "Health Score"}, "health_status": {"$ref": "#/components/schemas/HealthStatus"}, "eval_success_rate": {"anyOf": [{"type": "number"}, {"type": "null"}], "title": "Eval Success Rate"}, "feedback_ratio": {"anyOf": [{"type": "number"}, {"type": "null"}], "title": "Feedback Ratio"}, "data_quality_score": {"anyOf": [{"type": "number"}, {"type": "null"}], "title": "Data Quality Score"}, "schema_drift_flag": {"type": "boolean", "title": "Schema Drift Flag"}, "failure_wrong_table": {"type": "integer", "title": "Failure Wrong Table"}, "failure_wrong_sql": {"type": "integer", "title": "Failure Wrong Sql"}, "failure_empty_result": {"type": "integer", "title": "Failure Empty Result"}, "failure_execution_error": {"type": "integer", "title": "Failure Execution Error"}, "updated_at": {"type": "string", "format": "date-time", "title": "Updated At"}}, "type": "object", "required": ["id", "table_id", "health_score", "health_status", "eval_success_rate", "feedback_ratio", "data_quality_score", "schema_drift_flag", "failure_wrong_table", "failure_wrong_sql", "failure_empty_result", "failure_execution_error", "updated_at"], "title": "TableHealthRead"}, "TableProfileRead": {"properties": {"id": {"type": "string", "title": "Id"}, "table_id": {"type": "string", "title": "Table Id"}, "status": {"$ref": "#/components/schemas/ProfilingStatus"}, "row_count": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Row Count"}, "sample_size": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Sample Size"}, "column_count": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Column Count"}, "size_bytes": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Size Bytes"}, "null_rate_avg": {"anyOf": [{"type": "number"}, {"type": "null"}], "title": "Null Rate Avg"}, "duplicate_rate": {"anyOf": [{"type": "number"}, {"type": "null"}], "title": "Duplicate Rate"}, "sample_data": {"anyOf": [{}, {"type": "null"}], "title": "Sample Data"}, "auto_insights": {"anyOf": [{"items": {"type": "string"}, "type": "array"}, {"type": "null"}], "title": "Auto Insights"}, "profile_json": {"anyOf": [{}, {"type": "null"}], "title": "Profile Json"}, "cached_until": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "Cached Until"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "updated_at": {"type": "string", "format": "date-time", "title": "Updated At"}}, "type": "object", "required": ["id", "table_id", "status", "row_count", "sample_size", "column_count", "size_bytes", "null_rate_avg", "duplicate_rate", "sample_data", "auto_insights", "profile_json", "cached_until", "created_at", "updated_at"], "title": "TableProfileRead"}, "TableRead": {"properties": {"id": {"type": "string", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "schema_name": {"type": "string", "title": "Schema Name"}, "status": {"$ref": "#/components/schemas/TableStatus"}, "owner_id": {"type": "string", "title": "Owner Id"}, "oasis_source_id": {"type": "string", "title": "Oasis Source Id"}, "catalog": {"type": "string", "title": "Catalog"}, "service": {"type": "string", "title": "Service"}, "openmetadata_json": {"anyOf": [{"type": "object"}, {"type": "null"}], "title": "Openmetadata Json"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "updated_at": {"type": "string", "format": "date-time", "title": "Updated At"}}, "type": "object", "required": ["id", "name", "schema_name", "status", "owner_id", "oasis_source_id", "catalog", "service", "openmetadata_json", "created_at", "updated_at"], "title": "TableRead"}, "TableStatus": {"type": "string", "enum": ["draft", "sandbox", "verified", "production", "degraded"], "title": "TableStatus"}, "UserScopeCreate": {"properties": {"user_id": {"type": "string", "title": "User Id"}, "name": {"type": "string", "title": "Name"}}, "type": "object", "required": ["user_id", "name"], "title": "UserScopeCreate"}, "UserScopeRead": {"properties": {"id": {"type": "string", "title": "Id"}, "user_id": {"type": "string", "title": "User Id"}, "name": {"type": "string", "title": "Name"}, "is_active": {"type": "boolean", "title": "Is Active"}}, "type": "object", "required": ["id", "user_id", "name", "is_active"], "title": "UserScopeRead"}, "ValidationError": {"properties": {"loc": {"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, "type": "array", "title": "Location"}, "msg": {"type": "string", "title": "Message"}, "type": {"type": "string", "title": "Error Type"}}, "type": "object", "required": ["loc", "msg", "type"], "title": "ValidationError"}}}} |
There was a problem hiding this comment.
🔒 Security & Privacy | 🔵 Trivial
Static-analysis findings on the regenerated spec worth a second look.
- oasdiff flags ~50 paths as "removed without deprecation" (e.g.
POST /admin/login,GET /tables,POST /tables/{table_id}/eval/run). These all correspond to paths that were simply reprefixed with/api/..., which matches this PR's intended prefix migration — but for any consumer not using the generated TS client (docs, Postman collections, other-language SDKs, external integrations), this is a genuine breaking change with no deprecation window. Worth confirming there are no such external consumers before merging. - Checkov also flags no global
securityscheme/operations (CKV_OPENAPI_4/5) and arrays withoutmaxItems(CKV_OPENAPI_21) across many schemas (e.g.allowed_tables,coverage_tags). These are lower-priority hygiene gaps for an internal API but worth tracking if this spec is ever used for external-facing docs or codegen.
🧰 Tools
🪛 Checkov (3.3.8)
[high] 1: Ensure that the global security field has rules defined
(CKV_OPENAPI_4)
[high] 1: Ensure that security operations is not empty.
(CKV_OPENAPI_5)
[medium] 1: Ensure that arrays have a maximum number of items
(CKV_OPENAPI_21)
🪛 oasdiff (1.23.0)
[error] ~1-~1: api path removed without deprecation (POST /admin/login, section: paths, fingerprint: 2759666b2583)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /admin/tables/pending, section: paths, fingerprint: 5e85732b34b3)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /admin/tables/{table_id}/approve, section: paths, fingerprint: 1c283e376497)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /admin/tables/{table_id}/reject, section: paths, fingerprint: 1e8012be427a)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /audit/queries, section: paths, fingerprint: eff8254b2af2)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /eval/batch/{promotion_run_id}, section: paths, fingerprint: 01f2fd7fb4b2)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /eval/readiness, section: paths, fingerprint: 6bcee4db1f02)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /eval/runs/all, section: paths, fingerprint: 1237f53eb62e)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /eval/{run_id}, section: paths, fingerprint: a6dce4b89ad4)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /eval/{run_id}/regression-diff, section: paths, fingerprint: 086d107232dd)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /eval/{run_id}/report, section: paths, fingerprint: a6d65b63584f)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /eval/{run_id}/results, section: paths, fingerprint: af257c0f1a70)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /evaluations/alerts, section: paths, fingerprint: f88dbff231e0)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /evaluations/alerts/{alert_id}/acknowledge, section: paths, fingerprint: 6214d0ce6167)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /evaluations/analytics/tables, section: paths, fingerprint: 3b2a6260b1ae)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /evaluations/analytics/trends, section: paths, fingerprint: 85483129adc2)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /evaluations/compare, section: paths, fingerprint: c81fa982bb08)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /evaluations/run, section: paths, fingerprint: dc79feefa5c3)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /evaluations/runs, section: paths, fingerprint: 8b95774d7d8a)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /evaluations/runs/{run_id}, section: paths, fingerprint: 6f29bda06819)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /evaluations/runs/{run_id}/report, section: paths, fingerprint: 0173e5c298d2)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /evaluations/schedules, section: paths, fingerprint: 30121406599d)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /evaluations/schedules, section: paths, fingerprint: c4866ce58b1b)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (DELETE /evaluations/schedules/{schedule_id}, section: paths, fingerprint: 2de5a0004f2c)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (PUT /evaluations/schedules/{schedule_id}, section: paths, fingerprint: f1c13b9efba1)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /evaluations/system-health, section: paths, fingerprint: c4cf03c5408c)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /feedback, section: paths, fingerprint: 85b15c5cf6d8)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /feedback/query/{query_id}, section: paths, fingerprint: b064ce64f72b)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /feedback/table/{table_id}, section: paths, fingerprint: 4f1f62f4cf78)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /health/all, section: paths, fingerprint: 701cd4faf71a)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /scopes, section: paths, fingerprint: f7c4a8c32d3a)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /scopes, section: paths, fingerprint: 8c0e13f20548)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /scopes/{scope_id}/activate, section: paths, fingerprint: 346e4981ca18)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /tables, section: paths, fingerprint: 76500138535f)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /tables, section: paths, fingerprint: 1b3f63295784)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /tables/all/profile/run, section: paths, fingerprint: 48aec25271b5)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /tables/{table_id}, section: paths, fingerprint: a44bf0920021)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /tables/{table_id}/columns/{column}/profile, section: paths, fingerprint: 5a1ae6a194bb)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /tables/{table_id}/cross-profile, section: paths, fingerprint: a4e43d44c518)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /tables/{table_id}/cross-profile, section: paths, fingerprint: 2d275d067db5)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /tables/{table_id}/enrichment, section: paths, fingerprint: 531e9962bf89)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /tables/{table_id}/enrichment/latest, section: paths, fingerprint: 98278a6bcdf1)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /tables/{table_id}/eval/run, section: paths, fingerprint: 173951454ac9)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /tables/{table_id}/eval/runs, section: paths, fingerprint: 214244deadad)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /tables/{table_id}/health, section: paths, fingerprint: 9dd6e4850cd0)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /tables/{table_id}/health/recompute, section: paths, fingerprint: 8922bb9f39ad)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /tables/{table_id}/profile, section: paths, fingerprint: 05fdb4e4560e)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /tables/{table_id}/profile/columns, section: paths, fingerprint: 9c8242d2a41c)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /tables/{table_id}/profile/context, section: paths, fingerprint: 6faf52f7f154)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /tables/{table_id}/profile/run, section: paths, fingerprint: 98f1e54e51eb)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /tables/{table_id}/publish, section: paths, fingerprint: 1aec71000185)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /tables/{table_id}/questions, section: paths, fingerprint: 1b07e6905985)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /tables/{table_id}/questions, section: paths, fingerprint: 919d5aad6644)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /tables/{table_id}/questions/upload, section: paths, fingerprint: 585235c3a7ad)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (DELETE /tables/{table_id}/questions/{question_id}, section: paths, fingerprint: 2a9afa751245)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (PATCH /tables/{table_id}/status, section: paths, fingerprint: b4f5953ffb45)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /tables/{table_id}/sync-schema, section: paths, fingerprint: 792107022ecf)
(api-path-removed-without-deprecation)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@frontend/openapi.json` at line 1, Confirm that the intentional migration of
all endpoints to the /api prefix has no consumers outside the generated
TypeScript client; if external consumers exist, preserve legacy routes or add a
documented deprecation window before removing them. Track the separate OpenAPI
hygiene findings for global security declarations and maxItems constraints on
array schemas, without expanding this prefix-migration change unless required.
Source: Linters/SAST tools
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== files ==\n'
git ls-files 'backend/app/routers/agent.py' 'frontend/openapi.json' 'frontend/src/api/schema.d.ts' 'frontend/src/**/AgentTestingPage.tsx' | sed 's#^`#-` #'
for f in backend/app/routers/agent.py frontend/openapi.json frontend/src/api/schema.d.ts frontend/src/**/AgentTestingPage.tsx; do
[ -e "$f" ] || continue
printf '\n== %s (lines, size) ==\n' "$f"
wc -l "$f"
done
printf '\n== agent router snippets ==\n'
sed -n '1,220p' backend/app/routers/agent.py
printf '\n== schema.d.ts snippets around TraceSpan / get_trace_timeline ==\n'
rg -n "TraceSpan|get_trace_timeline|QueryApproval" frontend/src/api/schema.d.tsRepository: StavPonte11/text2sql-onboarding
Length of output: 8618
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== frontend/openapi.json TraceSpan / QueryApproval occurrences ==\n'
rg -n '"TraceSpan"|"QueryApproval"|/api/agent/traces/\{trace_id\}|rejection_category|suggested_fix' frontend/openapi.json
printf '\n== AgentTestingPage references ==\n'
rg -n 'rejection_category|suggested_fix|approved|feedback|QueryApproval' frontend/src/**/AgentTestingPage.tsxRepository: StavPonte11/text2sql-onboarding
Length of output: 50387
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
import json
from pathlib import Path
spec = json.loads(Path("frontend/openapi.json").read_text())
paths = spec.get("paths", {})
schemas = spec.get("components", {}).get("schemas", {})
trace = paths.get("/api/agent/traces/{trace_id}", {}).get("get", {})
qapp = schemas.get("QueryApproval", {})
print("trace_200_schema:", trace.get("responses", {}).get("200", {}).get("content", {}).get("application/json", {}).get("schema"))
print("has_TraceSpan_schema:", "TraceSpan" in schemas)
print("QueryApproval_properties:", list(qapp.get("properties", {}).keys()))
PY
printf '\n-- backend/app/routers/agent.py relevant lines --\n'
rg -n 'class TraceSpan|class QueryApproval|response_model=list\[TraceSpan\]|response_model' backend/app/routers/agent.py
printf '\n-- frontend/src/api/schema.d.ts relevant lines --\n'
rg -n 'TraceSpan|get_trace_timeline|QueryApproval' frontend/src/api/schema.d.tsRepository: StavPonte11/text2sql-onboarding
Length of output: 1062
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '1720,1742p' frontend/src/api/schema.d.tsRepository: StavPonte11/text2sql-onboarding
Length of output: 879
Regenerate this OpenAPI snapshot — it’s out of sync with the backend contract: /api/agent/traces/{trace_id} still has an empty 200 schema and no TraceSpan component, and QueryApproval still includes rejection_category/suggested_fix even though the backend model only has approved and feedback. Rebuild the spec and the generated frontend types from the current backend models.
🧰 Tools
🪛 Checkov (3.3.8)
[high] 1: Ensure that the global security field has rules defined
(CKV_OPENAPI_4)
[high] 1: Ensure that security operations is not empty.
(CKV_OPENAPI_5)
[medium] 1: Ensure that arrays have a maximum number of items
(CKV_OPENAPI_21)
🪛 oasdiff (1.23.0)
[error] ~1-~1: api path removed without deprecation (POST /admin/login, section: paths, fingerprint: 2759666b2583)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /admin/tables/pending, section: paths, fingerprint: 5e85732b34b3)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /admin/tables/{table_id}/approve, section: paths, fingerprint: 1c283e376497)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /admin/tables/{table_id}/reject, section: paths, fingerprint: 1e8012be427a)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /audit/queries, section: paths, fingerprint: eff8254b2af2)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /eval/batch/{promotion_run_id}, section: paths, fingerprint: 01f2fd7fb4b2)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /eval/readiness, section: paths, fingerprint: 6bcee4db1f02)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /eval/runs/all, section: paths, fingerprint: 1237f53eb62e)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /eval/{run_id}, section: paths, fingerprint: a6dce4b89ad4)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /eval/{run_id}/regression-diff, section: paths, fingerprint: 086d107232dd)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /eval/{run_id}/report, section: paths, fingerprint: a6d65b63584f)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /eval/{run_id}/results, section: paths, fingerprint: af257c0f1a70)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /evaluations/alerts, section: paths, fingerprint: f88dbff231e0)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /evaluations/alerts/{alert_id}/acknowledge, section: paths, fingerprint: 6214d0ce6167)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /evaluations/analytics/tables, section: paths, fingerprint: 3b2a6260b1ae)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /evaluations/analytics/trends, section: paths, fingerprint: 85483129adc2)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /evaluations/compare, section: paths, fingerprint: c81fa982bb08)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /evaluations/run, section: paths, fingerprint: dc79feefa5c3)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /evaluations/runs, section: paths, fingerprint: 8b95774d7d8a)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /evaluations/runs/{run_id}, section: paths, fingerprint: 6f29bda06819)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /evaluations/runs/{run_id}/report, section: paths, fingerprint: 0173e5c298d2)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /evaluations/schedules, section: paths, fingerprint: 30121406599d)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /evaluations/schedules, section: paths, fingerprint: c4866ce58b1b)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (DELETE /evaluations/schedules/{schedule_id}, section: paths, fingerprint: 2de5a0004f2c)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (PUT /evaluations/schedules/{schedule_id}, section: paths, fingerprint: f1c13b9efba1)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /evaluations/system-health, section: paths, fingerprint: c4cf03c5408c)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /feedback, section: paths, fingerprint: 85b15c5cf6d8)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /feedback/query/{query_id}, section: paths, fingerprint: b064ce64f72b)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /feedback/table/{table_id}, section: paths, fingerprint: 4f1f62f4cf78)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /health/all, section: paths, fingerprint: 701cd4faf71a)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /scopes, section: paths, fingerprint: f7c4a8c32d3a)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /scopes, section: paths, fingerprint: 8c0e13f20548)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /scopes/{scope_id}/activate, section: paths, fingerprint: 346e4981ca18)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /tables, section: paths, fingerprint: 76500138535f)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /tables, section: paths, fingerprint: 1b3f63295784)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /tables/all/profile/run, section: paths, fingerprint: 48aec25271b5)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /tables/{table_id}, section: paths, fingerprint: a44bf0920021)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /tables/{table_id}/columns/{column}/profile, section: paths, fingerprint: 5a1ae6a194bb)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /tables/{table_id}/cross-profile, section: paths, fingerprint: a4e43d44c518)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /tables/{table_id}/cross-profile, section: paths, fingerprint: 2d275d067db5)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /tables/{table_id}/enrichment, section: paths, fingerprint: 531e9962bf89)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /tables/{table_id}/enrichment/latest, section: paths, fingerprint: 98278a6bcdf1)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /tables/{table_id}/eval/run, section: paths, fingerprint: 173951454ac9)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /tables/{table_id}/eval/runs, section: paths, fingerprint: 214244deadad)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /tables/{table_id}/health, section: paths, fingerprint: 9dd6e4850cd0)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /tables/{table_id}/health/recompute, section: paths, fingerprint: 8922bb9f39ad)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /tables/{table_id}/profile, section: paths, fingerprint: 05fdb4e4560e)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /tables/{table_id}/profile/columns, section: paths, fingerprint: 9c8242d2a41c)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /tables/{table_id}/profile/context, section: paths, fingerprint: 6faf52f7f154)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /tables/{table_id}/profile/run, section: paths, fingerprint: 98f1e54e51eb)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /tables/{table_id}/publish, section: paths, fingerprint: 1aec71000185)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (GET /tables/{table_id}/questions, section: paths, fingerprint: 1b07e6905985)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /tables/{table_id}/questions, section: paths, fingerprint: 919d5aad6644)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /tables/{table_id}/questions/upload, section: paths, fingerprint: 585235c3a7ad)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (DELETE /tables/{table_id}/questions/{question_id}, section: paths, fingerprint: 2a9afa751245)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (PATCH /tables/{table_id}/status, section: paths, fingerprint: b4f5953ffb45)
(api-path-removed-without-deprecation)
[error] ~1-~1: api path removed without deprecation (POST /tables/{table_id}/sync-schema, section: paths, fingerprint: 792107022ecf)
(api-path-removed-without-deprecation)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@frontend/openapi.json` at line 1, The OpenAPI snapshot and generated frontend
types are stale. Regenerate the spec and frontend types from the current backend
models so `/api/agent/traces/{trace_id}` references the proper `TraceSpan`
response schema and `QueryApproval` contains only `approved` and `feedback`,
removing `rejection_category` and `suggested_fix`.
| const isDuplicate = data?.some( | ||
| (t) => | ||
| t.oasis_source_id === formData.oasis_source_id || | ||
| `${t.service}.${t.catalog}.${t.schema_name}.${t.name}` === formData.oasis_source_id || | ||
| `${t.catalog}.${t.schema_name}.${t.name}` === formData.oasis_source_id | ||
| ); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Client-side duplicate validation is bypassed when filters are active.
The data variable only contains tables matching the current search and status filters. If a duplicate table exists but is currently hidden by a filter, this check will incorrectly pass, causing the form validation to be bypassed and leading to an unexpected backend error message.
Use the global query cache to check against all fetched tables, mirroring the reliable approach used in the OnboardingWizard.
🐛 Proposed fix
const onSubmit = (formData: CreateSchemaType) => {
- const isDuplicate = data?.some(
- (t) =>
- t.oasis_source_id === formData.oasis_source_id ||
- `${t.service}.${t.catalog}.${t.schema_name}.${t.name}` === formData.oasis_source_id ||
- `${t.catalog}.${t.schema_name}.${t.name}` === formData.oasis_source_id
- );
+ const queriesData = qc.getQueriesData<Table[]>({ queryKey: ['tables'] });
+ const existingTables = queriesData.flatMap(([_, d]) => d || []);
+
+ const isDuplicate = existingTables.some(
+ (t) =>
+ t.oasis_source_id === formData.oasis_source_id ||
+ `${t.service}.${t.catalog}.${t.schema_name}.${t.name}` === formData.oasis_source_id ||
+ `${t.catalog}.${t.schema_name}.${t.name}` === formData.oasis_source_id
+ );📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const isDuplicate = data?.some( | |
| (t) => | |
| t.oasis_source_id === formData.oasis_source_id || | |
| `${t.service}.${t.catalog}.${t.schema_name}.${t.name}` === formData.oasis_source_id || | |
| `${t.catalog}.${t.schema_name}.${t.name}` === formData.oasis_source_id | |
| ); | |
| const onSubmit = (formData: CreateSchemaType) => { | |
| const queriesData = qc.getQueriesData<Table[]>({ queryKey: ['tables'] }); | |
| const existingTables = queriesData.flatMap(([_, d]) => d || []); | |
| const isDuplicate = existingTables.some( | |
| (t) => | |
| t.oasis_source_id === formData.oasis_source_id || | |
| `${t.service}.${t.catalog}.${t.schema_name}.${t.name}` === formData.oasis_source_id || | |
| `${t.catalog}.${t.schema_name}.${t.name}` === formData.oasis_source_id | |
| ); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@frontend/src/components/tables/TableList.tsx` around lines 86 - 91, Update
duplicate validation around isDuplicate in TableList to read the complete
fetched table collection from the global query cache rather than the filtered
data variable. Mirror the cache-access pattern used by OnboardingWizard, then
preserve the existing oasis_source_id and composite-name comparisons against all
cached tables.
| import { tablesApi } from '../api/client'; | ||
| import type { ChatRequest, ChatResponse } from '../api/agent'; | ||
| import type { Table } from '../types'; | ||
|
|
||
| import type { components } from '../api/schema'; | ||
| export type TraceSpan = components['schemas']['TraceSpan']; | ||
|
|
||
| export type ResumeValue = | ||
| | string | ||
| | Record<string, never> | ||
| | { approved: boolean; feedback?: string; }; | ||
|
|
||
|
|
||
| import styles from './AgentTestingPage.module.css'; | ||
|
|
||
| const agentConfigSchema = z.object({ | ||
| allowedStatuses: z.array(z.string()), | ||
| allowedTables: z.array(z.string()), | ||
| tableMode: z.enum(['inclusive', 'exclusive']), | ||
| hitlEnabled: z.boolean(), | ||
| extractors: z.array(z.string()), | ||
| activeSkills: z.array(z.string()), | ||
| executionMode: z.string().optional(), | ||
| }); | ||
| type AgentConfigValues = z.infer<typeof agentConfigSchema>; | ||
|
|
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
ResumeValue re-declares a shape that already exists in the generated schema.
ResumeValue's object variant ({ approved: boolean; feedback?: string; }) is a hand-rolled subset of QueryApproval (already exported from ../api/agent, which also has optional rejection_category/suggested_fix). Since this PR is specifically about typed resume payloads, deriving ResumeValue from the schema instead of a manual copy avoids future drift if QueryApproval changes again.
♻️ Proposed refactor
-export type ResumeValue =
- | string
- | Record<string, never>
- | { approved: boolean; feedback?: string; };
+export type ResumeValue = NonNullable<ChatRequest['resume_value']>;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| import { tablesApi } from '../api/client'; | |
| import type { ChatRequest, ChatResponse } from '../api/agent'; | |
| import type { Table } from '../types'; | |
| import type { components } from '../api/schema'; | |
| export type TraceSpan = components['schemas']['TraceSpan']; | |
| export type ResumeValue = | |
| | string | |
| | Record<string, never> | |
| | { approved: boolean; feedback?: string; }; | |
| import styles from './AgentTestingPage.module.css'; | |
| const agentConfigSchema = z.object({ | |
| allowedStatuses: z.array(z.string()), | |
| allowedTables: z.array(z.string()), | |
| tableMode: z.enum(['inclusive', 'exclusive']), | |
| hitlEnabled: z.boolean(), | |
| extractors: z.array(z.string()), | |
| activeSkills: z.array(z.string()), | |
| executionMode: z.string().optional(), | |
| }); | |
| type AgentConfigValues = z.infer<typeof agentConfigSchema>; | |
| import { tablesApi } from '../api/client'; | |
| import type { ChatRequest, ChatResponse } from '../api/agent'; | |
| import type { Table } from '../types'; | |
| import type { components } from '../api/schema'; | |
| export type TraceSpan = components['schemas']['TraceSpan']; | |
| export type ResumeValue = NonNullable<ChatRequest['resume_value']>; | |
| import styles from './AgentTestingPage.module.css'; | |
| const agentConfigSchema = z.object({ | |
| allowedStatuses: z.array(z.string()), | |
| allowedTables: z.array(z.string()), | |
| tableMode: z.enum(['inclusive', 'exclusive']), | |
| hitlEnabled: z.boolean(), | |
| extractors: z.array(z.string()), | |
| activeSkills: z.array(z.string()), | |
| executionMode: z.string().optional(), | |
| }); | |
| type AgentConfigValues = z.infer<typeof agentConfigSchema>; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@frontend/src/pages/AgentTestingPage.tsx` around lines 39 - 64, Replace the
hand-written object variant in ResumeValue with the existing QueryApproval type
exported from ../api/agent, while preserving the string and empty-record
variants. Update the import in AgentTestingPage.tsx to include QueryApproval and
derive ResumeValue from that schema type so future QueryApproval changes remain
reflected automatically.
| const config = watch(); | ||
| const allowed_statuses = config.tableMode === 'inclusive' ? config.allowedStatuses : []; | ||
|
|
||
| // Delay mutation slightly to allow SSE EventSource to connect | ||
| setTimeout(() => { | ||
| chatMutation.mutate({ | ||
| query, | ||
| thread_id: newThreadId, | ||
| hitl_enabled: hitlEnabled, | ||
| allowed_statuses: allowedStatuses.length > 0 ? allowedStatuses : undefined, | ||
| hitl_enabled: config.hitlEnabled, | ||
| allowed_statuses: allowed_statuses.length > 0 ? allowed_statuses : [], | ||
| allowed_tables: config.allowedTables.length > 0 ? config.allowedTables : undefined, | ||
| extractors: config.extractors.length > 0 ? config.extractors : undefined, | ||
| active_skills: config.activeSkills.length > 0 ? config.activeSkills : undefined, | ||
| execution_mode: config.executionMode || undefined, | ||
| }); | ||
| }, 300); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Map the relevant file and search for the request shape and table mode wiring.
git ls-files frontend/src/pages/AgentTestingPage.tsx frontend/src | sed -n '1,20p'
echo '--- AgentTestingPage outline ---'
ast-grep outline frontend/src/pages/AgentTestingPage.tsx --view expanded || true
echo '--- Search for tableMode / allowed_tables / allowed_statuses / ChatRequest ---'
rg -n "tableMode|allowed_tables|allowed_statuses|ChatRequest|Specific Tables|Table Mode|allowedTables|allowedStatuses" frontend/src -SRepository: StavPonte11/text2sql-onboarding
Length of output: 3763
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the exact section around the mutation and the nearby UI controls.
sed -n '430,490p' frontend/src/pages/AgentTestingPage.tsx
echo '---'
sed -n '1090,1135p' frontend/src/pages/AgentTestingPage.tsx
# Find the ChatRequest type definition and any server-side handling.
rg -n "type ChatRequest|interface ChatRequest|ChatRequest" frontend/src ../ -S --glob '!**/node_modules/**' || trueRepository: StavPonte11/text2sql-onboarding
Length of output: 50387
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect backend ChatRequest and how allowed_tables / allowed_statuses are used.
sed -n '1,260p' backend/app/routers/agent.py
echo '---'
rg -n "allowed_tables|allowed_statuses|tableMode|exclusive|inclusive" backend app agent frontend/openapi.json frontend/src/api/schema.d.ts -S \
--glob '!**/node_modules/**' | head -n 120Repository: StavPonte11/text2sql-onboarding
Length of output: 50387
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Focus on the request schema and exact handling, with bounded output.
python3 - <<'PY'
import json, re, pathlib
schema = json.loads(pathlib.Path('frontend/openapi.json').read_text())
chat = schema['components']['schemas']['ChatRequest']
print('ChatRequest keys:', sorted(chat['properties'].keys()))
print('required:', chat.get('required'))
for k in ['allowed_tables', 'allowed_statuses', 'hitl_enabled']:
print(k, '=>', chat['properties'].get(k))
PY
echo '--- backend/app/routers/agent.py around ChatRequest ---'
sed -n '1,120p' backend/app/routers/agent.py
echo '--- repo search for tableMode / allowed tables semantics ---'
rg -n "tableMode|allowed_tables|allowed_statuses|exclusive|inclusive" backend frontend -S \
--glob '!**/node_modules/**' --glob '!frontend/openapi.json' | head -n 120Repository: StavPonte11/text2sql-onboarding
Length of output: 6109
“Table Mode” only gates statuses here, not tables. tableMode never reaches ChatRequest, and allowed_tables is forwarded unchanged in both modes. If Exclusive is meant to exclude the selected tables, this is missing the wire-up; otherwise, rename/reposition the control so the status-only behavior is explicit. allowed_statuses.length > 0 ? allowed_statuses : [] is redundant.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@frontend/src/pages/AgentTestingPage.tsx` around lines 1105 - 1120, The chat
mutation setup in the AgentTestingPage currently applies tableMode only to
allowed_statuses while always forwarding allowedTables. Wire tableMode into the
ChatRequest so Exclusive mode excludes the selected tables, or explicitly
rename/reposition the control if it is intended to govern statuses only; also
simplify the redundant allowed_statuses empty-length expression while preserving
the request’s expected empty-array behavior.
Summary by CodeRabbit
New Features
Bug Fixes
API Updates