9.5 KiB
9.5 KiB
Data Model: LLM Analysis Plugin v2
Feature: 017-llm-analysis-plugin
Updated: 2026-05-31 — v2: ValidationPolicy expansion, ValidationSource, dual-path execution models
Entities
LLMProviderConfig
Stores configuration for different LLM providers.
| Field | Type | Required | Description |
|---|---|---|---|
| id | UUID | Yes | Unique identifier |
| provider_type | Enum | Yes | openai, openrouter, kilo, litellm |
| name | String | Yes | Display name (e.g., "Production GPT-4") |
| base_url | String | Yes | API Endpoint URL |
| api_key | String | Yes | Encrypted API Key (AES-256) |
| default_model | String | Yes | Model identifier (e.g., gpt-4o) |
| is_active | Boolean | Yes | Whether this provider is currently enabled |
| is_multimodal | Boolean | Yes | Whether model supports image input (required for Path A) |
ValidationPolicy (v2 — expanded)
Stores configuration for a scheduled validation task. Uses ORM relationship to ValidationSource table — no JSON column denormalization.
| Field | Type | Required | Description |
|---|---|---|---|
| id | UUID | Yes | Unique identifier |
| name | String | Yes | Human-readable task name |
| description | String | No | Optional description |
| environment_id | String | Yes | Target Superset environment |
| sources | relationship → list[ValidationSource] | Yes | ORM relationship only. Dashboards to validate (1..N). Migrated from v1 dashboard_ids list via ValidationSource rows |
| source_snapshot | JSON | No | Read-only denormalized copy of sources at last edit time — for audit/diff only, never used as authoritative state |
| provider_id | String | Yes | LLM provider to use (per-task, not global) |
| prompt_template | String | No | Custom prompt; null = use path-specific default: dashboard_validation_prompt_multimodal for Path A, dashboard_validation_prompt_text for Path B. Must NOT fall back to v1 legacy dashboard_validation_prompt |
| screenshot_enabled | Boolean | Yes | true = Path A (Playwright + multimodal LLM), false = Path B (text-only) |
| logs_enabled | Boolean | Yes | Fetch Superset execution logs for LLM context |
| execute_chart_data | Boolean | Yes | Path B only: execute POST /api/v1/chart/data for each chart (default: false) |
| llm_batch_size | Integer | No | Path B only: dashboards per LLM call (default: 1 — full isolation, one call per dashboard). Values >1 are experimental. Path A always uses 1 (image token constraints). |
| policy_dashboard_concurrency_limit | Integer | No | Max dashboards validated in parallel within one policy run (default: 3). Global worker limit controlled by global_validation_worker_limit config |
| cron_expression | String | No | Cron schedule; null = manual trigger only |
| is_active | Boolean | Yes | Whether schedule is currently active |
| notification_channels | list[String] | No | Email/Pulse channel IDs for failure notifications |
| created_at | DateTime | Yes | Creation timestamp |
| updated_at | DateTime | Yes | Last modification timestamp |
ValidationSource (new)
Represents a single dashboard to validate within a task — either by numeric ID or by full Superset URL.
| Field | Type | Required | Description |
|---|---|---|---|
| id | UUID | Yes | Unique identifier |
| policy_id | UUID | Yes | FK → ValidationPolicy |
| type | Enum | Yes | dashboard_id or dashboard_url |
| value | String | Yes | Numeric dashboard ID or full Superset URL |
| parsed_context | JSON | No | For dashboard_url: result of SupersetContextExtractor.parse_superset_link() — contains dashboard_id, native_filters, activeTabs, anchor |
| status | Enum | Yes | valid, partial_recovery (SupersetContextExtractor returned partial match), stale (permalink expired, URL parse warning), invalid (dashboard deleted or not found), permission_denied, parse_failed |
| resolved_dashboard_id | String | No | Resolved numeric dashboard ID (cached after URL parse for display) |
| title | String | No | Resolved dashboard title (cached for display) |
| last_error | String | No | Last resolution error message |
| last_checked_at | DateTime | No | When the source was last validated/resolved |
Migration from v1 dashboard_ids:
# Existing dashboard_ids: list[str] → ValidationSource rows (relational only, no JSON denormalization)
for dashboard_id in old_policy.dashboard_ids:
db.add(ValidationSource(
policy_id=policy.id,
type="dashboard_id",
value=dashboard_id,
is_valid=True,
))
# Optional: populate source_snapshot JSON for audit trail
policy.source_snapshot = {"dashboard_ids": list(old_policy.dashboard_ids)}
ValidationRun (new — groups records from one execution)
A single task execution validates ALL dashboards in a policy. ValidationRun groups these per-dashboard ValidationRecords into one logical unit.
| Field | Type | Required | Description |
|---|---|---|---|
| id | UUID | Yes | Unique run identifier |
| policy_id | UUID | Yes | FK → ValidationPolicy |
| task_id | String | No | Associated Task Manager task ID (one run = one task) |
| started_at | DateTime | Yes | When the run started |
| finished_at | DateTime | No | When all dashboards finished (null while running) |
| trigger | Enum | Yes | manual or scheduled |
| status | Enum | Yes | completed (all dashboards done), partial (some sources skipped/invalid), failed (execution error before any dashboard) |
| dashboard_count | Integer | Yes | Total dashboards attempted |
| pass_count | Integer | Yes | PASS results |
| warn_count | Integer | Yes | WARN results |
| fail_count | Integer | Yes | FAIL results |
| unknown_count | Integer | Yes | UNKNOWN results (LLM errors, timeouts) |
ValidationRecord (v2 — expanded, linked to run)
Stores the outcome of one dashboard validation within a task run. Linked to ValidationRun via run_id.
| Field | Type | Required | Description |
|---|---|---|---|
| id | UUID | Yes | Unique identifier |
| run_id | UUID | Yes | FK → ValidationRun — groups per-dashboard results from one task execution |
| task_id | String | No | Deprecated in favor of run_id; kept for v1 backward compat |
| policy_id | UUID | No | FK → ValidationPolicy |
| source_id | UUID | No | FK → ValidationSource |
| dashboard_id | String | Yes | Resolved dashboard ID |
| status | Enum | Yes | PASS, WARN, FAIL, UNKNOWN |
| execution_path | Enum | Yes | screenshot (Path A) or text_only (Path B) |
| summary | String | Yes | LLM-generated summary |
| issues | JSON | Yes | [{severity, message, location}] |
| dataset_health | JSON | No | Path B only: per-dataset status [{dataset_id, name, database, backend, healthy, error, affected_charts}] |
| chart_data_results | JSON | No | Path B with execute_chart_data=true: [{chart_id, executed, duration_ms, row_count, error}] |
| screenshot_paths | list[String] | No | Path A: paths to archived WebP screenshots (one per tab). PNG/JPEG intermediates deleted after conversion |
| tab_screenshots | JSON | No | Path A: per-tab mapping [{tab_name, webp_path, errored}] |
| logs_sent_to_llm | list[String] | No | Redacted Superset execution logs sent to LLM |
| token_usage | JSON | No | LLM token usage {prompt_tokens, completion_tokens, total_tokens} (when provider reports it) |
| raw_response | Text | No | Full LLM response for debugging. Retention: 30 days per FR-029a |
| timings | JSON | No | Phase timings: {dashboard_fetch_ms, dataset_fetch_ms, chart_fetch_ms, chart_data_exec_ms, screenshot_ms, llm_call_ms, total_ms} |
| created_at | DateTime | Yes | Record creation timestamp |
Path B — Dataset Health Check (runtime model, not persisted separately)
Built during Path B execution from API responses:
class DatasetHealth:
dataset_id: int
dataset_name: str # e.g. "finance.kpi_revenue"
database_name: str # e.g. "PostgreSQL / analytics_prod"
backend: str # e.g. "postgresql", "trino"
kind: str # "virtual" or "physical"
is_accessible: bool # HTTP 200 from GET /api/v1/dataset/{id}
error: str | None # Connection / timeout error
affected_chart_ids: list[int] # Charts using this dataset
Chart Execution Result (runtime model, Path B + execute_chart_data)
class ChartDataResult:
chart_id: int
chart_name: str
viz_type: str
executed: bool # False if skipped
duration_ms: int | None
row_count: int | None
error: str | None # Timeout / query error
API Contracts
See contracts/ directory.
Key Interactions — v2
- Configure Provider:
POST /api/llm/providers(unchanged) - Create Validation Task:
POST /api/validation-tasks— createsValidationPolicy+ValidationSources - List Tasks:
GET /api/validation-tasks— returns all policies with aggregated status - Get Task Detail:
GET /api/validation-tasks/{policy_id}— returns policy + per-source status - Trigger Run:
POST /api/validation-tasks/{policy_id}/run— manual trigger (also fires on cron) - Get Run History:
GET /api/validation-tasks/{policy_id}/runs— paginatedValidationRecordlist - Get Run Detail:
GET /api/validation-tasks/{policy_id}/runs/{record_id}— full report - Parse URL:
POST /api/validation-tasks/parse-url— returns{dashboard_id, title, filters, tabs}from URL - Generate Documentation:
POST /api/taskswithplugin_id=llm_documentation(unchanged) - Generate Commit Message:
POST /api/git/generate-message(unchanged)