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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user