{
  "schemaVersion": 1,
  "purpose": "Curated review aid for recurring Jarela operations. Entries identify canonical implementations and behavior tests; they are not an exhaustive dependency policy.",
  "patterns": [
    {
      "id": "icon-file-lifecycle",
      "operation": "Read avatar files through useIconFile so superseded, removed and unmounted selections cannot apply late results, and failures remain visible and retryable.",
      "canonicalSources": [
        "hooks/useIconFile.ts"
      ],
      "validationSources": [
        "hooks/useIconFile.test.tsx",
        "components/agents/agent-editor/useAgentEditorForm.test.tsx",
        "components/profile/ProfileEditor.test.tsx",
        "components/setup/wizard/StepAgent.test.tsx"
      ],
      "exceptions": [
        "The first-run picker retains its own 1 MB validation; agent and profile editors do not acquire that limit.",
        "Chat attachments use a different upload contract and are not avatar selections."
      ]
    },
    {
      "id": "workspace-layout",
      "operation": "Share workspace width, outer horizontal gutters, and docked sidebar dimensions through the workspace CSS tokens.",
      "canonicalSources": [
        "app/globals.css",
        "components/layout/AppShell.tsx",
        "components/ui/PanelHeader.tsx",
        "components/ui/SubTabBar.tsx"
      ],
      "validationSources": [
        "tests/e2e/layout.spec.ts",
        "components/dashboard/DashboardPanel.test.tsx"
      ],
      "exceptions": [
        "Dialogs, chat bubbles, nested cards, and the standalone onboarding wizard retain their content-specific sizing.",
        "The touch composer retains safe-area-specific horizontal padding for rounded-corner clearance."
      ]
    },
    {
      "id": "api-request-validation",
      "operation": "Validate JSON request bodies at API boundaries with a Zod schema and the shared response contract.",
      "canonicalSources": [
        "lib/api/responses.ts",
        "api/document-sources.ts",
        "api/memory.ts"
      ],
      "validationSources": [
        "lib/api/responses.test.ts",
        "api/document-sources.test.ts",
        "app/api/v1/memory/route.test.ts",
        "components/memory/MemoryEditor.test.tsx"
      ],
      "exceptions": [
        "Streaming, multipart, and non-JSON endpoints need their transport-specific parsing, but must still validate input explicitly."
      ]
    },
    {
      "id": "api-error-response",
      "operation": "Build compatible v1 HTTP errors with errorResponse or errorJson, preserving structured fields, statuses, headers and existing not-found wording.",
      "canonicalSources": [
        "lib/api/responses.ts",
        "lib/api/errors.ts"
      ],
      "validationSources": [
        "lib/api/responses.test.ts",
        "scripts/eslint-api-responses.test.mjs"
      ],
      "exceptions": [
        "HTTP-200 probe results and OAuth status payloads may contain error fields without being HTTP errors.",
        "SSE, binary, HTML, redirects and plain-text responses keep their transport-specific contracts."
      ]
    },
    {
      "id": "api-response-serialization",
      "operation": "Keep resource row-to-response mapping shared between collection and item routes to prevent shape drift.",
      "canonicalSources": [
        "lib/api/serializers.ts"
      ],
      "validationSources": [
        "lib/api/serializers.test.ts",
        "app/api/v1/documents/sources/contract.test.ts"
      ],
      "exceptions": [
        "Use a separate serializer when the public resource shapes or privacy rules intentionally differ."
      ]
    },
    {
      "id": "tolerant-json-decoding",
      "operation": "Use the shared JSON parser only when malformed or empty JSON has a documented fallback; validate user input separately.",
      "canonicalSources": [
        "lib/utils/json.ts",
        "lib/stores/app-settings-json.ts"
      ],
      "validationSources": [
        "lib/utils/json.test.ts",
        "lib/stores/app-settings-json.test.ts",
        "components/chat/chat-helpers.test.tsx",
        "lib/agents/conversation-summary.test.ts"
      ],
      "exceptions": [
        "Never use a fallback parser as a substitute for schema validation of a request or persisted value with integrity requirements."
      ]
    },
    {
      "id": "stored-message-decoding",
      "operation": "Decode legacy stored attachment arrays consistently for chat rendering and model history, preserving plain-text fallback and part order.",
      "canonicalSources": [
        "api/message-content.ts"
      ],
      "validationSources": [
        "api/message-content.test.ts",
        "components/chat/MessageBubble.test.tsx",
        "lib/agents/prepare/history-window.test.ts"
      ],
      "exceptions": [
        "Request validation and transcript/TTS text projection have different input and output contracts; stored decoding does not replace them."
      ]
    },
    {
      "id": "best-effort-context-deadline",
      "operation": "Bound waiting for optional context, returning the caller's fallback on timeout or rejection and clearing the timer on early settlement.",
      "canonicalSources": [
        "lib/utils/promise.ts"
      ],
      "validationSources": [
        "lib/utils/promise.test.ts",
        "lib/agents/prepare/history-window.test.ts",
        "lib/agents/run-thread.retry.test.ts"
      ],
      "exceptions": [
        "History treats non-positive budgets as unlimited waiting; foreground recall retains a zero-budget timer.",
        "This does not cancel execution and must not mask failures of required operations or authorization checks."
      ]
    },
    {
      "id": "bounded-keyed-cache",
      "operation": "Use the keyed TTL cache for recomputable values with explicit invalidation dependencies, or the bounded content cache for stable key/value mappings.",
      "canonicalSources": [
        "lib/cache/keyed-cache.ts"
      ],
      "validationSources": [
        "lib/cache/keyed-cache.test.ts"
      ],
      "exceptions": [
        "State requiring durability, cross-process sharing, or security-sensitive retention belongs in the appropriate store, not an in-memory cache."
      ]
    },
    {
      "id": "client-async-cache",
      "operation": "Share client list/value request coalescing, TTL, revision invalidation, superseded completion handling and owned failure cleanup; preserve shape-specific copying and notification adapters.",
      "canonicalSources": [
        "api/client.ts"
      ],
      "validationSources": [
        "api/client.cache.test.ts",
        "api/client.models.test.ts",
        "api/client.startup.test.ts"
      ],
      "exceptions": [
        "Synchronous keyed/content caches and startup handoff snapshots have different invalidation, copying and ownership contracts."
      ]
    },
    {
      "id": "model-inline-secret-policy",
      "operation": "Resolve echoed inline model-secret masks against the row read inside the mutation lock and redact the same fields on collection and mutation responses.",
      "canonicalSources": [
        "lib/models/inline-params.ts",
        "lib/utils/secret-mask.ts"
      ],
      "validationSources": [
        "lib/models/inline-params.test.ts",
        "app/api/v1/models/[name]/route.test.ts"
      ],
      "exceptions": [
        "Credential stores, integration forms and proxy settings retain their separate field sets, account boundaries and persistence contracts."
      ]
    },
    {
      "id": "built-in-tool-registration",
      "operation": "Register built-in tools with explicit category and capability metadata through the shared registry.",
      "canonicalSources": [
        "lib/tools/runtime/registry.ts"
      ],
      "validationSources": [
        "lib/tools/runtime/registry.test.ts",
        "lib/tools/runtime/capability-coverage.test.ts"
      ],
      "exceptions": [
        "MCP and external tools have separate loading and policy boundaries; do not force them through the built-in registration lifecycle."
      ]
    }
  ]
}
