Repository navigation
v3 households: save each calculated household to its user, shown nowhere - #1505
Conversation
After the Household tab calculates a household, v3 saves it to the session's user as a /v2/user-households row pointing at the v1 household (legacy_household_id), as it already saves reforms and reports through the Public API. Nothing in v3 reads these rows yet; they keep each user's households for the Public API's v2 household routes. - ApiFlagshipHouseholdStore.saveCalculated looks for the user's row for the household first and creates one only when there is none, named with the household's summary (shortened to the API's limit). - useSaveCalculatedHousehold saves in the background, once per household and session (one query key per household), and only where saved work goes to the account: signed in, or signed out as the browser's unauthenticated user, in the account's country. A failed save changes nothing on the page. Tests first: the store's and the hook's tests failed to import the missing code, and the section's test failed because no calculated household was passed on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ave per session - A browser signed out that saved only households (a report someone else ran, then a household calculated on it) was told at sign-in that its reforms and reports had moved to the account: the household save creates the browser's unauthenticated user, so the upgrade no longer answers "none". Both sign-in notices now speak of the work saved on this browser. - The save's cache entry is kept for the session (gcTime), so the same household is not looked up again after five minutes. - The hook takes the calculated household as one value (its v1 ID and summary), and the report's CountryId. - Tests: the signed-out save as the browser's unauthenticated user, one lookup as well as one save for the same household twice, the failed save held by its own query, and the household summary in the shared fixtures. Tests first: the notice test failed on both messages naming reforms and reports. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A signed-in session whose token could not be renewed ends without a reload, and saved work moves to the browser's unauthenticated user (a new session scope). The save's query key held that scope, so the household on screen was looked up and saved again as the browser's user, and the next sign-in merged that row into the account beside the one already there. The key now holds only the country and the v1 household, so a household saved on the page is not saved again. - The hook's comment says what it does: once saved, not looked up or saved again on the page; a failed save is tried again the next time the household's result shows. - A test that shows the same household again after six minutes, which fails without the session-long cache entry. - The fixture's summary is written as the Household tab writes it. Tests first: the session-end test failed with four requests instead of the signed-in lookup and save. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… of the retry - V3SavedWork.scope said a session that ends without a reload moves every query to new keys; the calculated household's save is not keyed by it, so the comment now says so. - A test that a failed save is tried again when the household's result shows again, as the hook's comment says. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Heads-up from Pavel's side: #1511 reworks the v3 Household tab's layout (a row of household tiles, Results/Inputs per household, Compare all, full-width charts). Saving stays here; #1511 saves nothing. The two overlap in
#1392 also overlaps ( 🤖 Generated with Claude Code |
PavelMakarchuk
left a comment
There was a problem hiding this comment.
Review: no blocking issues. The save lookup filters on legacy_household_id server-side, the hook sits before any early return, and a shared fetchQuery keeps a doubled effect (strict mode, or the same household twice) to one request. Three small points:
- A failed save leaves no trace (inline below).
- Stale comment, not in this diff:
householdRun.tsaboverunFlagshipHouseholdsays "the API dedupes identical ones". It does not: two identicalPOST /us/householdcalls today returned 58663 and 58664. Since this PR now saves a row per v1 household, worth correcting here so nobody expects one row per household after a reload. - Test gap: every hook test uses one
CALCULATED_HOUSEHOLD. A test with two household ids expecting two POSTs would catch someone droppinghouseholdIdfrom the query key.
Product note, not a defect: a signed-out visitor who only calculated a household now sees "The work you saved on this browser is now in your account" at sign-in, though they saved nothing visible. The description says this is deliberate; flagging it for Pavel's call.
🤖 Generated with Claude Code
| gcTime: Infinity, | ||
| retry: false, | ||
| }) | ||
| .catch(() => { |
There was a problem hiding this comment.
Every failure is dropped silently. If the API refuses all saves (a 422 on the body, a 403 for the browser's user), the rows never appear and nobody can tell. A console.error('[useSaveCalculatedHousehold] Save failed:', error) here changes nothing on the page, like runAccountUpgrade does.
🤖 Generated with Claude Code
There was a problem hiding this comment.
Done in 81a90cd: a failed save is now logged with console.error('[useSaveCalculatedHousehold] Save failed:', error), as runAccountUpgrade does, and the page stays as it was. A new test checks the log.
…ehold anew
From review:
- A failed save was dropped silently, so a Public API that refused
every save (a 422 on the body, a 403 for the browser's user) left
no trace. It is now logged with console.error, as the sign-in
upgrade logs its failure; the page is unchanged.
- runFlagshipHousehold's comment said the API dedupes identical
households. It does not: the Public API's POST /{country}/household
stores a new one on every call, so each run gets its own household
ID (and, with this PR, its own saved row).
- A test with two different households expecting two saves, which
fails if the household's ID is dropped from the save's query key.
- The hook's comment also says a failed save is tried again when the
session's user changes while the result shows.
Tests first: the logging test failed, as nothing was logged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks. Addressed in 81a90cd:
Not changed here: the sign-in notice's wording, and the saved row's name (still the household's summary). On #1511: whichever PR merges second keeps the |
What changes
v3's Household tab (on a report or bill page) calculates households through the Public API's v1 household routes and keeps each household only in the page's state. This PR saves each household it calculates to the user, in the background, as a
/v2/user-householdsrow that points at the v1 household (legacy_household_id), as v3 already saves its reforms and reports. Nothing in v3 reads or shows these rows yet: they keep each user's households for the Public API's v2 household routes.Saved only where saved work goes to the account (
useV3SavedWork): signed in, or signed out as the browser's unauthenticated user, in the US or UK, and only in the account's country. With sign-in off, nothing is saved.One row per v1 household and user.
ApiFlagshipHouseholdStore.saveCalculatedlooks up the user's row for the v1 household (GET /v2/user-householdsfiltered bylegacy_household_id) and creates one only when there is none. The row is named with the household's summary ("Married · 2 children · California"), shortened to the API's 255 characters.Once per page.
useSaveCalculatedHouseholdsaves through one query per country and household, kept for the page's life, so a saved household is not looked up again. The key leaves out the session's user: otherwise a signed-in session that ends without a reload would save the household on screen again as the browser's user, and the next sign-in would merge that row into the account beside the first. A failed save changes nothing on the page: it is logged to the console, and tried again the next time the household's result shows, or when the session's user changes while it shows.Sign-in notices. The household save creates the browser's unauthenticated user on the Public API, so a browser that saved only households now has work to move at sign-in. Both notices now say "The work you saved on this browser…" instead of naming reforms and reports.
Corrected comment.
runFlagshipHousehold's comment said the API dedupes identical households; it now says the Public API stores a new one on every call.Not changed: the Account page's delete dialog and signed-out card still name reforms and reports.
Known limits:
POST /{country}/householdstores a new v1 household on every call, so the same inputs calculated again (after a reload, or once the run's five-minute cache entry has gone) get a new v1 ID and a second row. Those rows point at the same v2 household, because the Public API's copies to v2 deduplicate identical content, so a view of saved households can group them byhousehold_id.Live as soon as it merges.
Tests
New or changed, all passing, each run by name:
flagshipHouseholdStore.test.ts(new): a household the user hasn't saved gets one row, after a lookup bylegacy_household_id; an existing row means no second one; a long summary is shortened; an ID that isn't a v1 household ID sends nothing.useFlagshipHousehold.test.tsx(new): the same household twice on a page is looked up and saved once, and isn't looked up again after six minutes; two different households are each saved; signed out, it's saved as the browser's unauthenticated user; with sign-in off, in another country, or with no calculated household, nothing is sent; a session that ends on the page saves nothing again; a failed save is logged to the console, stays in its own query, and is tried again when the result shows again.HouseholdImpactSection.test.tsx: a calculated household is passed on to be saved, with its v1 ID and summary.accountUpgrade.test.ts(new): the sign-in notices name no reforms or reports.Each failed before its code, except three that cover behaviour already in place: the six-minute test (it fails without the session-long cache entry), the two-household test (it fails without the household's ID in the query key) and the retry test.
🤖 Generated with Claude Code