Files
ss-tools/specs/017-llm-analysis-plugin/research.md
2026-06-08 14:14:38 +03:00

8.9 KiB
Raw Blame History

Research: LLM Analysis & Documentation Plugins v2

Feature: 017-llm-analysis-plugin Updated: 2026-06-07 — v2 implemented: dual-path execution, multi-chunk screenshots, dataset health checking, URL-based dashboards

v2 Research Decisions

8. Task-Based Flow (replaces ad-hoc Validate)

Decision: Remove one-click «Validate» button; replace with «Create Validation Task» flow (name → sources → provider+prompt → schedule).

Rationale: Ad-hoc validation doesn't scale — users need repeatable, scheduled checks with full configuration control. The task list provides visibility into what's running and historical trends.

Alternatives Considered:

  • Keep Validate button + add scheduling separately — rejected: two modes cause confusion; task-based is cleaner.
  • Inline validation from dashboard detail — rejected: no scheduling, no multi-dashboard runs.

9. Dual Execution Paths (Screenshot vs Text-Only)

Decision: screenshot_enabled flag controls execution path:

  • Path A (screenshot_enabled=true): Playwright → multi-chunk CDP screenshots → multimodal LLM
  • Path B (screenshot_enabled=false): API calls → dashboard topology + chart params + dataset health + logs → text-only LLM

Rationale:

  • Screenshot catches visual bugs (empty charts, overlap, rendering) but costs image tokens and requires a browser.
  • Text-only catches data/KXD errors (dataset inaccessible, chart query timeout) and is lightweight.
  • Together they cover both visual and data-layer failure modes. Users choose per task based on what matters.

Alternatives Considered:

  • Always screenshot — rejected: expensive, slow, doesn't check dataset backend health.
  • Always text-only — rejected: misses visual rendering bugs (broken charts with no error in logs).
  • Hybrid: screenshot + dataset check in one call — rejected: mixes modalities, increases LLM context size, complicates prompt.

10. Multi-Chunk Screenshots (Path A)

Decision: Instead of one compressed full-page screenshot, capture each dashboard tab as a separate high-resolution screenshot (max 1920×1200 per chunk). Send all chunks in a single multimodal LLM request.

Rationale: Long dashboards (5000+ px) compressed to 1024×2048 lose readability — small chart labels become unreadable. Per-tab chunks preserve resolution, and LLM sees the dashboard in the same logical sections a human would.

Alternatives Considered:

  • Single full-page at 4096px width — rejected: token cost too high for image processing.
  • Overlapping chunks with stitching — rejected: complex, fragile to viewport changes.
  • Per-chart screenshots — rejected: too many images (30+ charts → excessive tokens), loses layout context.

11. Dataset Health Checking (Path B)

Decision: For Path B, call GET /api/v1/dataset/{id} for every unique dataset used by dashboard charts. Verify: HTTP 200, database backend, kind (virtual/physical). Optionally execute POST /api/v1/chart/data (off by default).

Rationale: The primary purpose of LLM validation is verifying the KXD→dataset→chart→dashboard chain works. Screenshot-only misses silent data failures (empty results, partial data, wrong time range). Dataset health check catches KXD connection errors that produce no visual error but return empty/incomplete data.

Alternatives Considered:

  • Logs-only (no dataset API calls) — rejected: logs show past failures, not current KXD connectivity. A dataset can be broken right now with no recent log entry.
  • Always execute chart data — rejected: overloads Superset (15 charts × 30 dashboards = 450 queries). Optional toggle lets users enable selectively.

12. URL-Based Dashboard Selection

Decision: Support pasting full Superset dashboard URLs as task sources. Parse via SupersetContextExtractor (same code path as dataset review feature). Extract: dashboard_id, native_filters, activeTabs, anchor.

Rationale: Users copy dashboard URLs from browser with filters already applied. Parsing the URL preserves the exact filter/tab state — the validation checks the dashboard in the same state the user sees. Reusing SupersetContextExtractor avoids duplicating URL parsing logic.

URL Formats Supported (same as dataset review):

  • https://superset.example.com/superset/dashboard/42/ — numeric ID
  • https://superset.example.com/superset/dashboard/my-dashboard/ — slug
  • https://superset.example.com/superset/dashboard/p/abc123/ — permalink
  • https://superset.example.com/superset/dashboard/42/?native_filters_key=xyz — filter state key

Alternatives Considered:

  • Dashboard ID only — rejected: loses filter context, user must manually re-apply filters.
  • Custom URL format — rejected: users already have Superset URLs in browser; pasting them is natural.

13. Provider & Prompt Per-Task

Decision: Provider selection and prompt template configuration move from global LLM settings to per-task configuration in the task creation form. Global LLM settings retain provider bindings only for: documentation, git_commit, assistant_planner.

Rationale: Different dashboards may need different models (e.g., GPT-4o for complex visual analysis, a cheaper model for text-only). Different teams may want different prompt emphasis (performance vs. data quality). Global settings are too coarse.

Alternatives Considered:

  • Global binding + per-task override — rejected: adds complexity; per-task is simpler and more flexible.
  • Environment-level provider binding — rejected: too coarse; same environment may have different validation needs per dashboard group.

v1 Research Decisions (preserved)

1. LLM Provider Integration

Decision: Use a unified LLMProviderService that abstracts OpenAI-compatible APIs. Rationale: OpenRouter, Kilo, LiteLLM, and OpenAI all support the standard OpenAI API format.

2. Dashboard Screenshot Capture

Decision: ScreenshotService with Playwright + CDP for Path A. Rationale: Provides accurate «user-view» render; CDP avoids font loading timeouts in headless mode.

3. Multimodal Analysis Prompting

Decision: Structured prompt template accepting base64-encoded images + text logs. Rationale: GPT-4o / Claude / Gemini models support this natively.

4. Documentation Persistence

Decision: Update Dataset/Column models in metadata database. Rationale: Documentation co-located with assets.

5. Git Commit Integration

Decision: REST endpoint /api/git/generate-message. Rationale: Heavy lifting (LLM, diff processing) on backend.

6. Security & Storage

Decision: AES-256 encrypted API keys. Rationale: Keys must not be stored in plain text.

7. Retry Logic

Decision: tenacity with exponential backoff (5 attempts, 5-60s wait). Rationale: Standard, robust retry for transient LLM API failures.

14. Image Pipeline: PNG → JPEG (LLM) + WebP (Archive)

Decision: CDP captures PNG (browser-native, lossless). Convert to JPEG quality=60 for LLM (universal provider compatibility). Convert to WebP quality=80 for archive (93% disk savings vs PNG). Delete PNG and JPEG intermediates after successful save.

Rationale: JPEG universally supported by all providers. WebP has silent failure risk on unknown/closed providers (model accepts request but doesn't process image → false PASS). Pipeline decoupled: LLM failure doesn't affect archive; archive failure falls back to PNG with WARN.

Alternatives Considered:

  • All WebP (LLM + archive) — rejected: silent failure risk.
  • All JPEG (LLM + archive) — rejected: no archive space savings, re-encoding artifacts.
  • WebP for LLM with _supports_webp() per-provider check — rejected: adds complexity; JPEG is simpler and universally safe.

Impact: T017a, T017b, T017c in task plan. FR-059 in spec. D10 design decision. ~93% disk savings vs PNG archive.

15. Path B Batching (experimental v2.1)

Decision: Default llm_batch_size=1 (full isolation, one LLM call per dashboard). Values >1 are experimental and reduce cost at risk of cross-dashboard context contamination.

Rationale: Multiple dashboards in one LLM call saves API calls (5→1) but risks the LLM confusing which issue belongs to which dashboard. Structured prompt with per-dashboard labeled sections + strict JSON {dashboards: [{dashboard_id, ...}]} schema mitigates but does not eliminate this risk. For validation (where accuracy > cost), isolation is the safer default.

Alternatives Considered:

  • Always batch (default 5) — rejected: accuracy risk for validation feature. Can't guarantee LLMs won't cross-contaminate context.
  • Never batch (always 1) — rejected: legitimate use case for large fleet monitoring where cost matters more than per-dashboard precision.
  • Per-policy toggle only — accepted as the right balance: default safe, user opts into batching when they understand the tradeoff.

Impact: FR-045a in spec. llm_batch_size field in ValidationPolicy, default 1. Batch_size >1 is documented as experimental with known accuracy risk.