feat(prices): Settings revocation toggle for price_fetching_consent (#159) #168
1 changed files with 0 additions and 70 deletions
|
|
@ -1,70 +0,0 @@
|
||||||
# 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 `<button role="switch">`.
|
|
||||||
This is consistent with the rest of the codebase which uses inline Tailwind patterns rather
|
|
||||||
than an external component library. If a shared toggle is needed later, extract from here.
|
|
||||||
|
|
||||||
## Issue #159 — settings.privacy.title key added (LOW)
|
|
||||||
|
|
||||||
The `settings.privacy` i18n namespace only had `priceFetchConsent.*` keys — no `title`
|
|
||||||
for the section header. Added `settings.privacy.title` in both FR and EN locales.
|
|
||||||
|
|
||||||
## Issue #156 — rate-limit pacing test strategy (LOW)
|
|
||||||
|
|
||||||
The pacing test verifies that setTimeout is called with a positive delay for the 2nd
|
|
||||||
and 3rd concurrent calls, rather than asserting exact wall-clock timestamps via
|
|
||||||
Date.now(). This is because vi.useFakeTimers() advances Date.now() via timer
|
|
||||||
advancement, not automatically between microtasks. The spy approach is more resilient
|
|
||||||
to vitest internals and fake-timer edge cases.
|
|
||||||
Loading…
Reference in a new issue