chore: drop decisions-log.md (autopilot scratch, conflicts with main cleanup)
All checks were successful
PR Check / rust (push) Successful in 23m34s
PR Check / frontend (push) Successful in 2m30s
PR Check / rust (pull_request) Successful in 23m22s
PR Check / frontend (pull_request) Successful in 2m27s

This commit is contained in:
le king fu 2026-04-27 21:35:57 -04:00
parent 80c28d43ac
commit a6097afcf3

View file

@ -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.