feat(backend): add v2 LLM validation fields to health service

- DashboardHealthItem schema: add run_id, policy_id, execution_path,
  issues_count, timings, token_usage, screenshot_paths, chunk_count,
  dashboard_name fields for v2 LLM validation reporting.
- HealthService: populate v2 fields from validation run records.
- ValidationService: update to support v2 validation run fields.
- validation_tasks route: minor fix for v2 field handling.
- tailwind.config.js: refactor design tokens — add success/warning/info
  palettes, surface/border/text hierarchy, semantic action colors.
- Agent configs: update svelte-coder and semantics-svelte for
  .svelte.ts runes and Screen Model patterns.
This commit is contained in:
2026-06-02 09:54:42 +03:00
parent 4fc3356312
commit 8219540ade
7 changed files with 307 additions and 135 deletions

View File

@@ -48,13 +48,14 @@ See `semantics-core` §VI for the canonical tool reference. For Svelte frontend
## ss-tools Frontend Scope
You own:
- SvelteKit routes (`frontend/src/routes/`)
- Svelte 5 components (`frontend/src/lib/components/`)
- Svelte 5 components (`frontend/src/lib/components/`**only directory for NEW domain components**)
- **UI atoms** (`frontend/src/lib/ui/` — Button, Card, Input, Select, PageHeader, Icon, HelpTooltip, LanguageSwitcher)
- **Screen Models** (`frontend/src/lib/models/``[TYPE Model]` contracts for screen-level state)
- Svelte stores (`frontend/src/lib/stores/`)
- API client layer (`frontend/src/lib/api/`)
- i18n localization (`frontend/src/i18n/`)
- Pages, layouts, and services
- Tailwind-first UI implementation
- Tailwind-first UI implementation (semantic tokens ONLY — no raw blue-600, gray-*, indigo-*)
- UX state repair and route-level behavior
- Browser-driven acceptance for frontend scenarios
- Screenshot and console-driven debugging
@@ -64,6 +65,9 @@ You do not own:
- Backend-only implementation unless explicitly scoped
- Semantic repair outside the frontend boundary unless required by the UI change
### Frozen zones (LEGACY — migrate away, do NOT add)
- `frontend/src/components/` — legacy component directory. **Do not create new files here.** All new domain components go in `lib/components/<domain>/`.
## Required Workflow
1. **Discover or create the Model first.** For any screen with cross-widget state:
- grep `@semantics.*<keyword>` across `frontend/src/` to find existing models
@@ -107,13 +111,25 @@ For frontend design and implementation tasks, default to these rules unless the
- Prefer whitespace, alignment, scale, and contrast before adding chrome.
- Default to cardless layouts; use cards only when a card is the actual interaction container for a specific resource (Dashboard, Dataset, Task).
### Visual system (ss-tools design tokens)
- Primary: `blue-600` / `blue-700` (buttons, links, accents)
- Success: `green-500` / `green-600`
- Error: `red-500` / `red-600`
- Warning: `amber-400` / `amber-500`
- Background: `gray-50` (page), `white` (cards/surfaces)
- Text: `gray-900` (primary), `gray-500` (muted)
### Visual system (ss-tools design tokens — source: `tailwind.config.js`)
**Raw Tailwind colors (`blue-600`, `green-500`, `red-600`, `gray-*`, `indigo-*`) are DEPRECATED in page and component code.** Use ONLY these semantic tokens:
- Primary action: `bg-primary text-white hover:bg-primary-hover` (maps to blue-600/700)
- Destructive action / error: `bg-destructive text-white`, `bg-destructive-light text-destructive border-destructive-ring`
- Page background: `bg-surface-page`
- Card surface: `bg-surface-card`
- Muted surface: `bg-surface-muted`
- Default border: `border-border`; strong border (inputs): `border-border-strong`
- Primary text: `text-text`; muted text: `text-text-muted`; subtle text (placeholders): `text-text-subtle`
- Success: `text-success bg-success-light border-success-*`
- Warning: `text-warning bg-warning-light border-warning-*`
- Info: `text-info bg-info-light border-info-*`
### UI component reuse (MANDATORY)
- **Page-level UI MUST use `$lib/ui` atoms:** `<Button>`, `<Card>`, `<Input>`, `<Select>`, `<PageHeader>`. Raw `<button>` and manual `<div class="bg-white rounded...">` in page files is a violation unless there is a documented exception.
- **`src/components/` is LEGACY FROZEN.** Do not create new files there. Do not extend it. New domain components go in `src/lib/components/<domain>/`.
- **`migration/+page.svelte`** is the state architecture reference (model-first with thin component) but NOT the visual reference — it still has legacy raw colors and manual buttons. Use the canonical template in `semantics-svelte` §VI for visual patterns.
- **Button variant naming:** Use `"destructive"` (canonical). `"danger"` is a deprecated alias — prefer `"destructive"`.
### ss-tools specific pages
- **Dashboard Hub** — Git-tracked dashboards with status badges

View File

@@ -11,7 +11,10 @@ description: Svelte 5 (Runes) protocol for ss-tools: UX State Machines, Tailwind
@RATIONALE Svelte 5 runes ($state, $derived, $effect, $props) chosen for reactive precision and native compiler optimisations over Svelte 4 legacy reactivity ($:). Tailwind CSS selected for zero-runtime utility-first styling and rapid visual validation via chrome-devtools MCP. FSM-based UX contracts (@UX_STATE, @UX_FEEDBACK, @UX_RECOVERY) chosen to create verifiable state-transition tests that the browser Judge Agent can execute deterministically. ss-tools internal API wrappers (fetchApi/requestApi) chosen over native fetch to enforce auth, error normalisation, and trace_id propagation.
@REJECTED React (JSX) rejected — Svelte's compiler-first approach yields smaller bundles and native reactivity without virtual DOM overhead. Vue rejected — Svelte 5 runes provide simpler mental model. Legacy Svelte 4 syntax (export let, $:, on:event) rejected — incompatible with Svelte 5 runes mode. CSS Modules / styled-components rejected in favour of Tailwind's utility-first approach, which avoids style leakage and simplifies chrome-devtools visual diffing. Native fetch() rejected — bypasses ss-tools middleware chain (auth, trace_id, error normalisation). Plain-text logging rejected per MolecularCoTLogging §VII — JSON lines are mandatory for agent-parsable traces.
@INVARIANT Frontend components MUST be verifiable by the browser toolset via `chrome-devtools` MCP.
@INVARIANT Use Tailwind CSS exclusively. Native `fetch` is forbidden — use `requestApi`/`fetchApi` wrappers.
@INVARIANT Use Tailwind CSS exclusively. Raw Tailwind color classes (`blue-600`, `green-500`, `red-600`, `gray-*`, `indigo-*`) are DEPRECATED in page and component code — use semantic tokens from `tailwind.config.js` only (`primary`, `destructive`, `success`, `warning`, `surface-*`, `border-*`, `text-*`).
@INVARIANT Page-level UI MUST use `$lib/ui` atoms: `<Button>`, `<Card>`, `<Input>`, `<Select>`, `<PageHeader>`. Raw `<button>` elements and manual card `<div>` containers in page files are a violation.
@INVARIANT `src/components/` is LEGACY FROZEN. New domain components go in `src/lib/components/<domain>/`. Do not create new files under `src/components/`.
@INVARIANT Native `fetch` is forbidden — use `requestApi`/`fetchApi` wrappers.
## 0. SVELTE 5 PARADIGM & UX PHILOSOPHY (SS-TOOLS)
@@ -319,17 +322,19 @@ Region format for HTML/Svelte comments:
<!-- @RELATION BINDS_TO -> [notificationStore] -->
<!-- @UX_STATE Idle -> Default card view with task summary. -->
<!-- @UX_STATE Loading -> Action button disabled, spinner active, progress bar animated. -->
<!-- @UX_STATE Error -> Red border, error icon, retry button visible. -->
<!-- @UX_STATE Success -> Green border, checkmark, duration displayed. -->
<!-- @UX_STATE Error -> Card border + bg use destructive tokens, retry button visible. -->
<!-- @UX_STATE Success -> Card border + bg use success tokens, checkmark, duration displayed. -->
<!-- @UX_FEEDBACK Toast notification on start/fail/complete. -->
<!-- @UX_FEEDBACK Drawer opens on "View Logs" click. -->
<!-- @UX_RECOVERY Retry button on error. Clear/Cancel on running task. -->
<!-- @UX_REACTIVITY Props -> $props(), LocalState -> $state(isLoading, error). -->
<!-- @UX_TEST: Idle -> {click: "Run Migration", expected: Loading -> Success toast}. -->
<script>
<!-- @RATIONALE Uses semantic tokens (destructive-light, success-light, border, surface-card) instead of raw Tailwind (red-*, green-*, gray-*). Uses $lib/ui Button instead of raw <button>. This is the canonical visual reference for all components. -->
<script lang="ts">
import { fetchApi } from "$lib/api";
import { log } from "$lib/cot-logger";
import { t } from "$lib/i18n";
import { Button } from "$lib/ui";
import { taskDrawerStore } from "$lib/stores";
import { notificationStore } from "$lib/stores";
import StatusBadge from "./StatusBadge.svelte";
@@ -338,8 +343,8 @@ Region format for HTML/Svelte comments:
let { taskId, dashboardName, sourceEnv, targetEnv } = $props();
let isLoading = $state(false);
let error = $state(null);
let status = $state("idle");
let error: string | null = $state(null);
let status: "idle" | "loading" | "success" | "error" = $state("idle");
async function handleRunMigration() {
isLoading = true;
@@ -355,8 +360,8 @@ Region format for HTML/Svelte comments:
notificationStore.add({ type: "success", message: $t("migration.completed", { name: dashboardName }) });
} catch (e) {
status = "error";
error = e.message;
log("MigrationTaskCard", "EXPLORE", "Migration failed", { taskId }, error = e.message);
error = e instanceof Error ? e.message : "Migration failed";
log("MigrationTaskCard", "EXPLORE", "Migration failed", { taskId }, error);
notificationStore.add({ type: "error", message: $t("migration.failed", { name: dashboardName }) });
} finally {
isLoading = false;
@@ -369,17 +374,21 @@ Region format for HTML/Svelte comments:
}
</script>
<!-- @RATIONALE Card uses semantic surface/border/text tokens. Dynamic state uses destructive/success token families. Button component from $lib/ui instead of raw <button> tags. -->
<div
class="rounded-lg border p-4 transition-colors {status === 'error' ? 'border-red-500 bg-red-50' : ''} {status === 'success' ? 'border-green-500 bg-green-50' : 'border-gray-200 bg-white'}"
class="rounded-lg p-4 transition-colors
{status === 'error' ? 'border border-destructive-ring bg-destructive-light' : ''}
{status === 'success' ? 'border border-success-DEFAULT bg-success-light' : ''}
{status !== 'error' && status !== 'success' ? 'border border-border bg-surface-card' : ''}"
role="region"
aria-label={$t("migration.task_card", { name: dashboardName })}
>
<div class="flex items-center justify-between mb-2">
<h3 class="font-semibold text-gray-900">{dashboardName}</h3>
<h3 class="font-semibold text-text">{dashboardName}</h3>
<StatusBadge status={status} />
</div>
<div class="text-sm text-gray-500 mb-3">
<div class="text-sm text-text-muted mb-3">
{$t("migration.from")}: {sourceEnv} → {$t("migration.to")}: {targetEnv}
</div>
@@ -388,45 +397,80 @@ Region format for HTML/Svelte comments:
{/if}
{#if error}
<p class="text-sm text-red-600 mb-2" aria-live="polite">{error}</p>
<p class="text-sm text-destructive mb-2" aria-live="polite">{error}</p>
{/if}
<div class="flex gap-2 mt-3">
<button
class="btn-primary text-sm"
<Button
variant="primary"
size="sm"
onclick={handleRunMigration}
disabled={isLoading}
aria-busy={isLoading}
isLoading={isLoading}
>
{#if isLoading}
<span class="spinner mr-1" aria-hidden="true"></span>
{/if}
{status === "error" ? $t("actions.retry") : $t("actions.run")}
</button>
<button class="btn-secondary text-sm" onclick={handleViewLogs}>
</Button>
<Button variant="secondary" size="sm" onclick={handleViewLogs}>
{$t("actions.view_logs")}
</button>
</Button>
</div>
</div>
<!-- #endregion MigrationTaskCard -->
```
## VII. SS-TOOLS TAILWIND CONVENTIONS
## VII. SS-TOOLS DESIGN TOKEN CANON & COMPONENT REUSE
### Design tokens (from project config)
- Primary: `blue-600` / `blue-700` (buttons, links, accents)
- Success: `green-500` / `green-600`
- Error: `red-500` / `red-600`
- Warning: `amber-400` / `amber-500`
- Background: `gray-50` (page), `white` (cards)
- Text: `gray-900` (primary), `gray-500` (muted)
### Design tokens (source of truth: `frontend/tailwind.config.js`)
### Component class conventions
- Page layout: `max-w-7xl mx-auto px-4 py-6`
- Card: `bg-white rounded-lg shadow-sm border border-gray-200 p-4`
- Button primary: `bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 disabled:opacity-50`
- Button secondary: `border border-gray-300 text-gray-700 px-4 py-2 rounded-md hover:bg-gray-50`
- Table: `min-w-full divide-y divide-gray-200`
**Raw Tailwind colors (`blue-600`, `green-500`, `red-600`, `gray-*`, `indigo-*`) are DEPRECATED in page-level and component code.** Use ONLY semantic tokens below.
| Purpose | Token | Maps to |
|---------|-------|---------|
| Primary action | `text-primary bg-primary hover:bg-primary-hover` | blue-600/700 |
| Destructive action / error surface | `text-destructive bg-destructive-light border-destructive-ring` | red family |
| Page background | `bg-surface-page` | near-white |
| Card surface | `bg-surface-card` | white |
| Muted surface (hover/filter bars) | `bg-surface-muted` | gray-100 |
| Default border | `border-border` | gray-200 |
| Strong border (inputs, focus) | `border-border-strong` | gray-300 |
| Primary text | `text-text` | near-black |
| Muted text (secondary, captions) | `text-text-muted` | gray-500 |
| Subtle text (placeholders) | `text-text-subtle` | gray-400 |
| Success | `text-success bg-success-light border-success-*` | green family |
| Warning | `text-warning bg-warning-light border-warning-*` | amber family |
| Info | `text-info bg-info-light border-info-*` | sky family |
### Component reuse rules (MANDATORY for page-level code)
| Rule | Requirement |
|------|------------|
| **$lib/ui mandatory** | All page files (`src/routes/**/+page.svelte`) MUST import from `$lib/ui` for buttons, cards, inputs, selects, page headers. Raw `<button>` and `<div class="bg-white rounded...">` in page files are a violation unless covered by a documented exception. |
| **Component directory** | New domain components go in `src/lib/components/<domain>/`. `src/components/` is **LEGACY FROZEN** — do not add new files, do not extend, migrate out only. |
| **Button variants** | Use `<Button variant="primary">` (default), `<Button variant="secondary">`, `<Button variant="destructive">`, `<Button variant="ghost">`. The string `"danger"` is kept as a deprecated alias for `"destructive"` — prefer `"destructive"`. |
| **Page layout** | `<div class="max-w-7xl mx-auto px-4 py-6">` or `<div class="mx-auto w-full px-4 lg:px-8 space-y-6">`. |
| **Table pattern** | `min-w-full divide-y divide-border` — border via token. |
### Canonical semantic token reference (copy-paste for agents)
```
// ✅ CORRECT — semantic tokens
bg-surface-page // page background
bg-surface-card // card container
bg-surface-muted // filter bar, secondary button hover
border-border // card border, table divider
border-border-strong // input border, select border
text-text // heading, body
text-text-muted // secondary label, caption
text-text-subtle // placeholder
bg-primary text-white // primary action button
bg-destructive-light // error surface
text-destructive // error text
border-destructive-ring // error border
// ❌ WRONG — raw Tailwind (deprecated in page/component code)
bg-blue-600 text-blue-700 bg-gray-50 bg-white border-gray-200
text-gray-900 text-gray-500 bg-red-50 border-red-400 bg-green-50
bg-indigo-50 text-indigo-700 bg-gradient-to-br from-slate-50 via-white to-sky-50
```
## VIII. VITEST CONVENTIONS