# Decisions Log — /autopilot run of 2026-04-27 ## Issue #156 — session cap budget policy (MEDIUM) The 100-request session cap is checked BEFORE rate-limit enforcement and in-flight deduplication. Successful fetches increment the counter; failures (4xx, 5xx, network) do NOT consume the budget. Rationale: a user who hits a bad symbol or an auth error should not have their session budget drained by error conditions outside their control. This is the most user-friendly interpretation of "hard 100/session cap" while still protecting against runaway loops. ## Issue #156 — __resetForTests helper exported from prices namespace (LOW) The `prices.__resetForTests()` helper is exported alongside `fetchPrice`. This avoids the need for `vi.resetModules()` + dynamic import between tests, which is flakier and slower. The helper is named with `__` prefix to signal test-only usage. Alternative considered: module-level export — rejected because it would pollute the public API surface of balance.service outside the prices namespace. ## Issue #158 — no @testing-library/react or jsdom in project (MEDIUM) The project has no `@testing-library/react`, no jsdom, and no happy-dom configured in vitest. PriceFetchControl.test.tsx therefore uses direct unit tests of the component's internal logic (hook calls, service calls, state transitions) via mocked dependencies rather than DOM rendering. This tests behavior but not DOM structure. If the project later adopts RTL, these tests should be rewritten with render() + getByRole/getByText. Not adding RTL in autopilot mode (would require npm install permission). ## Issue #158 — user_preferences table is per-profile by architecture (LOW) Each profile has its own SQLite database file (confirmed in ProfileContext). The `user_preferences` table has no `profile_id` column — the profile scoping is implicit (each DB = one profile). Therefore the consent key `price_fetching_consent` does NOT need a profile_id prefix; the key alone is sufficient for correct per-profile scoping. ## Issue #158 — asset_type not in category schema (MEDIUM) The `balance_categories` table has no `asset_type` column (confirmed by schema.sql). The PriceFetchControl receives `assetType` prop from the parent. SnapshotLineRow/SnapshotEditor do not yet carry asset_type. Per autopilot decision policy, defaulting to `'stock'` as hardcoded fallback in SnapshotEditor wiring. A `// TODO: asset_type from category schema` comment marks the injection point. A follow-up issue should add `asset_type TEXT DEFAULT 'stock'` to `balance_categories` and thread it through SnapshotEditor props. ## Issue #159 — deletePreference added to userPreferenceService (LOW) The `userPreferenceService` had no `deletePreference` function. Added a simple DELETE SQL helper alongside `getPreference`/`setPreference`. Revoke must DELETE the row entirely (not set value to null) so that `PriceFetchControl` re-shows the consent modal on next click (it checks `getPreference` returning a truthy value). Setting to null would break that check. ## Issue #159 — no Switch/Toggle component in shared/ (MEDIUM) No reusable Switch or Toggle component exists in `src/components/shared/`. A minimal toggle was built inline inside `PriceFetchConsentToggle` using a styled `