Files
ss-tools/.opencode/skills/semantic-frontend/SKILL.md
2026-05-08 10:07:05 +03:00

6.3 KiB

name, description
name description
semantics-frontend Core protocol for Svelte 5 (Runes) Components, UX State Machines, and Visual-Interactive Validation.

[DEF:Std:Semantics:Frontend]

@COMPLEXITY 5

@PURPOSE Canonical GRACE-Poly protocol for Svelte 5 (Runes) Components, UX State Machines, and Project UI Architecture backed by Python APIs.

@RELATION DEPENDS_ON ->[Std:Semantics:Core]

@INVARIANT Frontend components MUST be verifiable by an automated GUI Judge Agent (e.g., Playwright).

@INVARIANT Use Tailwind CSS exclusively. Native fetch is forbidden.

0. SVELTE 5 PARADIGM & UX PHILOSOPHY

  • STRICT RUNES ONLY: You MUST use Svelte 5 Runes for reactivity: $state(), $derived(), $effect(), $props(), $bindable().
  • FORBIDDEN SYNTAX: Do NOT use export let, on:event (use onclick), or the legacy $: reactivity.
  • UX AS A STATE MACHINE: Every component is a Finite State Machine (FSM). You MUST declare its visual states in the contract BEFORE writing implementation.
  • RESOURCE-CENTRIC: Navigation and actions revolve around Resources. Every action MUST be traceable.
  • PYTHON BACKEND INTEGRATION: All API calls target a Python backend. Use the internal requestApi / fetchApi wrappers. The backend uses FastAPI or similar Python web frameworks.

I. PROJECT ARCHITECTURAL INVARIANTS

You are bound by strict repository-level design rules. Violating these causes instant PR rejection.

  1. Styling: Tailwind CSS utility classes are MANDATORY. Minimize scoped <style>. If custom CSS is absolutely necessary, use @apply directives.
  2. Localization: All user-facing text MUST use the $t store from src/lib/i18n. No hardcoded UI strings.
  3. API Layer: You MUST use the internal requestApi / fetchApi wrappers. Using native fetch() is a fatal violation. The backend API is written in Python (FastAPI, Django, or Flask).

II. UX CONTRACTS (STRICT UI BEHAVIOR)

Every component MUST define its behavioral contract in the header.

  • @UX_STATE: Maps FSM state names to visual behavior. Example: @UX_STATE Loading -> Spinner visible, btn disabled, aria-busy=true.
  • @UX_FEEDBACK: Defines external system reactions (Toast, Shake, RedBorder).
  • @UX_RECOVERY: Defines the user's recovery path from errors (e.g., Retry button, Clear Input).
  • @UX_REACTIVITY: Explicitly declares the state source. Example: @UX_REACTIVITY: Props -> $props(), LocalState -> $state(...).
  • @UX_TEST: Defines the interaction scenario for the automated Judge Agent. Example: @UX_TEST: Idle -> {click: submit, expected: Loading}.

III. STATE MANAGEMENT & STORE TOPOLOGY

  • Subscription: Use the $ prefix for reactive store access (e.g., $sidebarStore).
  • Graph Linkage: Whenever a component reads or writes to a global store, you MUST declare it in the [DEF] header metadata using: @RELATION BINDS_TO -> [Store_ID]

IV. IMPLEMENTATION & ACCESSIBILITY (A11Y)

  1. Event Handling: Use native attributes (e.g., onclick={handler}).
  2. Transitions: Use Svelte's built-in transitions for UI state changes to ensure smooth UX.
  3. Async Logic: Any async task (API calls to Python backend) MUST be handled within a try/catch block that explicitly triggers an @UX_STATE transition to Error on failure and provides @UX_FEEDBACK (e.g., Toast).
  4. A11Y: Ensure proper ARIA roles (aria-busy, aria-invalid) and keyboard navigation. Use semantic HTML (<nav>, <main>).

V. LOGGING (MOLECULAR TOPOLOGY FOR UI)

Frontend logging bridges the gap between your logic and the Judge Agent's vision system.

  • [EXPLORE]: Log branching user paths or caught UI errors.
  • [REASON]: Log the intent before an API invocation to the Python backend.
  • [REFLECT]: Log visual state updates (e.g., "Toast displayed", "Drawer opened").
  • Syntax: console.info("[ComponentID][MARKER] Message", {extra_data}) — Prefix MUST be manually applied.

VI. PYTHON BACKEND INTEGRATION PATTERNS

When implementing API interactions in Svelte components:

  1. Request wrappers: Always use requestApi(path, options) or fetchApi(path, options) — never raw fetch().
  2. DTO alignment: Frontend request/response shapes MUST match the Python backend's Pydantic models or dataclass schemas.
  3. Error handling: Python backend may return structured error responses (e.g., {"detail": "Validation error", "errors": [...]}). Parse and surface these to the user via @UX_FEEDBACK.
  4. Authentication: Use the centralized auth store. Python backend tokens (JWT, session cookies) are managed transparently by the API wrappers.

VII. CANONICAL SVELTE 5 COMPONENT TEMPLATE

You MUST strictly adhere to this AST boundary format:

<!-- [DEF:ComponentName:Component] -->
<script>
  /**
   * @COMPLEXITY [1-5]
   * @PURPOSE Brief description of the component purpose.
   * @LAYER UI
   * @SEMANTICS list, of, keywords
   * @RELATION DEPENDS_ON -> [OtherComponent]
   * @RELATION BINDS_TO -> [GlobalStore]
   * 
   * @UX_STATE Idle -> Default view.
   * @UX_STATE Loading -> Button disabled, spinner active.
   * @UX_FEEDBACK Toast notification on success/error.
   * @UX_REACTIVITY Props -> $props(), State -> $state().
   * @UX_TEST Idle -> {click: action, expected: Loading}
   */
  import { fetchApi } from "$lib/api";
  import { t } from "$lib/i18n";
  import { taskDrawerStore } from "$lib/stores";
  
  let { resourceId } = $props();
  let isLoading = $state(false);

  async function handleAction() {
    isLoading = true;
    console.info("[ComponentName][REASON] Opening task drawer for resource", { resourceId });
    try {
      taskDrawerStore.open(resourceId);
      // Calls Python backend endpoint (e.g., FastAPI route)
      await fetchApi(`/api/resource/${resourceId}/process`);
      console.info("[ComponentName][REFLECT] Process completed successfully");
    } catch (e) {
      console.error("[ComponentName][EXPLORE] Action failed", { error: e });
    } finally {
      isLoading = false;
    }
  }
</script>

<div class="flex flex-col p-4 bg-white rounded-lg shadow-md">
  <button 
    class="btn-primary" 
    onclick={handleAction} 
    disabled={isLoading}
    aria-busy={isLoading}
  >
    {#if isLoading} <span class="spinner"></span> {/if}
    {$t('actions.start')}
  </button>
</div>
<!--[/DEF:ComponentName:Component] -->

[/DEF:Std:Semantics:Frontend]

[SYSTEM: END OF FRONTEND DIRECTIVE. ENFORCE STRICT UI COMPLIANCE.]