Skip to content

feat: name the app's state machines and fix the shared patterns behind their bugs (2.36.0) - #286

Merged
Sagargupta16 merged 1 commit into
mainfrom
feat/explicit-state-machines
Nov 9, 2026
Merged

Sagargupta16 merged 1 commit into
mainfrom
feat/explicit-state-machines

Conversation

@Sagargupta16

Copy link
Copy Markdown
Owner

What and why

An audit of the whole repo found about 130 implicit state machines: lifecycles spread over booleans, nullables and flag combinations instead of one named state. They are now listed in docs/STATE_MACHINES.md with their states, owner and known gaps. The real bugs came from a few repeated shapes, so the fixes are shared pieces used everywhere, not local patches.

Problem Fix Reach
"Figures are out of date" after a successful recompute (an import that emptied the latest month left no fresh stamp) _rollup_freshness also counts AnalyticsState.published_at backend
A failed background refetch replaced data on screen with the error screen pageStatus + RefreshFailedNotice: error only when a read has nothing to show, Retry refetches only failed reads about 30 pages and panels
Retry briefly showed "No transactions" or zeros useStablePeriodData never commits a read that failed without data 6 period pages
Confirm dialogs closed before the action finished ConfirmDialog phases idle, pending, failed; callers pass the action promise 10 dialogs
Double error toasts markErrorReported; the global fallback waits one task and skips reported errors 8 sites
An offline save spun forever mutations use networkMode: 'always' like queries every save
Loading or failed AI config was treated as app-funded; double send; silent drop useAiAvailability for chat, Ask AI, weekly recap, Canvas; synchronous in-flight guard in useChat AI
A demo tab could replace a real sign-in another tab stored the demo session is not written to the shared ledger-sync-auth entry auth
Stale banner dismissal hid every later warning; sign-in re-enabled during redirect; a failed rate fetch read as "no rate" small fixes in each banner, sign-in, currency

The conventions are now a rule in .claude/rules/shared-patterns.md and a pointer in CLAUDE.md. No migration, no API shape change. Version 2.36.0.

Verified

  • Red then green on the old and new code for each new regression test: trailing-month freshness (test_data_health.py), period retry (useStablePeriodData.test.tsx), demo persistence (authStore.test.ts), dialog pending and failed (ConfirmDialog.test.tsx), one toast per failure (queryClient.test.ts).
  • vitest related on every changed source file: 85 files, 623 tests pass, plus 6 files, 32 tests after the follow-ups. tsc -b, eslint on all 110 files, pnpm build, pre-commit hooks: clean.
  • Backend: 70 tests across data health, analytics refresh and AI tools pass; ruff and mypy clean.
  • Browser, demo mode at 375x812: all 32 protected routes render with their heading, no error screen, no console errors. A forced refetch failure on Data Health kept the page and showed the notice; Retry cleared it. A confirm dialog opens with ids resolving to its own title.

Not verified

  • The dialog's pending and failed states in the live app: demo blocks every confirm before it reaches the server; unit tests render the real component for both.
  • Whether the production banner reported after the 2.35.0 upload was this trailing-month case or a refresh that really failed.
  • The full local test suites (CI runs them).

Held for a decision (listed in the doc)

Recording why a commitment is paused (needs a column), goal pause and cancel, AI funding after a key is removed, sweeping dead usage reservations, showing expired automation tokens.

@Sagargupta16
Sagargupta16 merged commit 55ed054 into main Nov 9, 2026
14 checks passed
@Sagargupta16
Sagargupta16 deleted the feat/explicit-state-machines branch November 9, 2026 04:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant