Repository navigation
Conversation
- BASE_URL now comes from VITE_API_URL (calculator-app: NEXT_PUBLIC_API_URL), defaulting to https://api.policyengine.org, so staging builds can use the staging API. - next.config.ts maps NEXT_PUBLIC_API_URL, NEXT_PUBLIC_AUTH_ENABLED and NEXT_PUBLIC_AUTH0_{DOMAIN,CLIENT_ID,AUDIENCE} (or their VITE_* spellings) onto import.meta.env.VITE_* for the shared app code. - Add @auth0/auth0-react to app and calculator-app. - Document the calculator environment in calculator-app/.env.example. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign-in (inert unless NEXT_PUBLIC_AUTH_ENABLED=true and Auth0 is configured):
- libs/auth: AuthProvider wraps @auth0/auth0-react (memory cache, rotating
refresh tokens with fallback, audience + offline_access) and loads the
PolicyEngine user from GET /v2/me for US/UK; useAuthStatus() exposes
status, user, signIn, signOut and getAccessToken. Without the provider,
or with sign-in off, status is 'disabled'.
- Mount the provider in [countryId]/providers.tsx and add the
/[countryId]/callback route that completes sign-in and returns to
appState.returnTo (same-origin paths only).
Account storage:
- v2UserClient: bearer-token fetch wrapper for ${BASE_URL}/v2/..., parsing
the {status, message, result} envelope and throwing V2ApiError(status).
- useAssociationBackend(): API stores only when signed in with a loaded
PolicyEngine user AND the country is US or UK; otherwise localStorage,
unchanged. Queries wait while the session is restored, and query keys
carry the PolicyEngine user ID (or 'anonymous') so caches split.
- Rewrite ApiPolicyStore/ApiHouseholdStore/ApiSimulationStore/ApiReportStore
and their adapters for /v2/user-{policies,households,simulations,reports}:
numeric legacy_*_id <-> string IDs, the association UUID as id,
list/get/create/update/delete, never a user_id. The API report store has
no createWithId (shared-report saves POST {legacy_report_id}), and local
sur- IDs resolve through this browser's import map or fall back to
localStorage so old links keep working.
- Replace every hard-coded isLoggedIn = false and the local simulation
store in createReportSimulations; pass the session's user ID instead of
MOCK_USER_ID. Saved geographies stay in localStorage for everyone; drop
the unused ApiGeographicStore and dead association payload types.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…abase path
Signed in (US/UK):
- Reforms are /v2/user-policies rows. Saving materializes the parameters
as a v1 policy (POST /{country}/policy, which dedupes) and stores
{legacy_policy_id, name, baseline, provenance}; parameter edits create a
new v1 policy and repoint legacy_policy_id; reading rebuilds parameters
from the v1 policy with the app's policy -> parameter conversion. A reform
kept only in this browser is added to the account when saved.
- Flagship report records are /v2/user-reports rows with the v3 fields
(title <-> name, sourceNote, provisions incl. dated intervals, validation,
reformId <-> user_policy_id). runFlagshipReport writes exactly one
association right after the v1 report exists; the report page reads the
account record for provenance on other devices.
Signed out (and outside the US and UK) the v3 stores use localStorage
exactly as before, now without first trying the never-provisioned
/api/reforms and /api/reports routes.
Remove those Next route handlers, calculator-app/src/db (Drizzle schema,
migrations, postgres-js client), DATABASE_URL, the PGlite route tests, the
drizzle/postgres/neon/pglite dependencies and db:* scripts, and the
storeBackend switch they relied on.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- AuthMenu: "Sign in" when signed out, a user menu (initial, My account, Sign out) when signed in, nothing when sign-in is disabled. Shown in the calculator header (desktop and mobile) and in the flagship top bar, which replaces that header when the flagship shell is on. - Sidebar "My account" links to the account page when sign-in is enabled. - Account page (/[countryId]/account, also replacing the Vite router placeholder): user details, "Download my data" (GET /v2/me/export), "Delete my account" (confirm, DELETE /v2/me, sign out), and saving this device's work to the account. - First sign-in import (US/UK): when the browser holds saved work the account lacks, offer "Save the work on this device to your account?". Gathers the policy/household/simulation/report associations, reforms, flagship records and provenance stash; materializes reforms without a v1 policy; merges a flagship run's sur-/lfr- records into one report; POSTs /v2/me/imports per country in chunks of at most 500 items (and about 1 MB); reports Canada/Nigeria/Israel items as staying on the device; persists the id_map (per user) so old local links resolve; and never deletes local data. "Not now" is remembered. - README: how sign-in and saved work behave, and the variables to set. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Account policy rows include policies saved from the legacy builder. v3 reforms always carry provenance and legacy policies never do, so the reform store now reads only rows with provenance. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@auth0/auth0-react 2.27.0 resolved @auth0/auth0-spa-js 2.28.3 (published 2026-10-09) and @auth0/auth0-auth-js 1.16.1 (2026-10-02). Override them to 2.27.0 and 1.15.0, both published in September. Re-locked with the pinned bun 1.2.21. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The API reports items it cannot parse as skipped with a null client_ref. Keep them in the summary but out of the per-ref skip bookkeeping. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This was referenced Oct 12, 2026
Open
Open
Saved-work queries wait until the session is restored, because until then it is not known whether saved work is in the account or in this browser. A waiting TanStack query is neither loading nor holding data, so report pages said "Report not found", flagship sur- links were marked unresolvable, and lists showed their empty state. With sign-in enabled this hit signed-out visitors too. The association hooks now go through useSessionGatedQuery, which reports a query that is waiting for the session as loading. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
If GET /v2/me failed (after one retry) the session became 'authenticated'
with no PolicyEngine user, so the store switch quietly chose
localStorage: the header still showed the user menu, new saves stayed on
this device, and nothing retried until a remount.
- A US or UK session whose PolicyEngine user could not be loaded is now
'account_error'. It gets the account stores backed by a client that
rejects every call with AccountUnavailableError, so lists and reports
show an error and saves fail with a clear message instead of going to
localStorage. A flagship run is refused up front, as it is while the
session is still being restored.
- /v2/me retries three times with backoff (1s, 2s, 4s), then again when
the window regains focus or the network comes back, and on
retryAccount.
- The user menu marks the avatar, says the account could not be loaded,
and offers "Try again" alongside "Sign out"; the account page offers
both too.
- selectAssociationBackend takes the user as-is, removing the
`{ id } as MeItem` cast.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An item the import sent that came back in neither id_map nor skipped
(the server reports unparseable items without a client_ref) stayed
pending, so LocalDataImportPrompt reopened on every visit, and closing
it after an import recorded nothing.
- Every item the server did not save is now recorded as skipped, with
the server's reason or as invalid, and appears once in the summary.
- Closing the prompt after an import ran ("Done", or closing after a
failure) is remembered like "Not now"; the account page still offers
what is left.
- The summary only says that what an item refers to no longer exists for
unknown_legacy_reference skips; other skips read "could not be saved".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed in, each account store handled an ID that only this browser knows (saved while signed out, never imported) differently: the report store read and updated the local copy, the policy, household and simulation stores answered 404, and the reform store created a fresh row without recording the rf- mapping, so a later import added the reform again. One policy now lives in AccountAssociationRoutes and every store follows it: an imported local ID resolves to its account row; any other local ID is read from this browser; changing it copies it into the account under its local ID as client_ref and records the mapping (on a 409, the existing row with that client_ref is updated instead); deleting it deletes this browser's copy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…owser - A signed-in run stashed its title, source note and provisions in localStorage under the v1 report ID, where whoever used this browser next would see them on that report. Signed-in runs now keep that provenance in memory for the session; the account record carries it everywhere else. - Signing out clears that stash and the draft reform, which may hold an account reform loaded for editing. - Import bookkeeping stays filed per PolicyEngine user. Items one account imported from this browser are no longer offered to a different account that signs in here; deleting the importing account releases them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The client's fallback for a 422 said "Something this refers to no longer
exists", but the Public API also answers 422 for request validation, and
the 409 fallback said every conflict was "managed elsewhere", although a
duplicate client_ref conflicts too. Both now name the likely causes
instead of asserting one. (The `{ id } as MeItem` cast went with the
account-error change.)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
While the session was being restored (and /v2/me now retries for up to about 7s), the store hooks handed out the localStorage stores, so a signed-in user's save in that window landed in this browser. - The auth context gains settledSession(): it answers once the status leaves 'loading', with the state the session settled in. useAssociationBackendResolver turns that into the backend for the country. - Every saved-work store the hooks hand out (policies, households, simulations, reports, reforms, flagship report records) now forwards each call to the store for the settled session. That covers the association mutations and the direct writers: the report builder's submission and modify hooks, useCreateReport, ReportAdjustPanel, DraftHeader and the Reforms page. useSaveSharedReport and the flagship run resolve the backend the same way; the run no longer errors while the session restores. - Signed-out visitors wait only for the restore, then save locally. - The v2 client asks for the access token at request time, so a request that waited carries the signed-in user's token. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
useCreatePolicy, useCreateHousehold and useCreateSimulation create the v1 artifact and then save its association, catching an association failure with console.error only. That was harmless while saves went to localStorage; with account storage a 413, a 503 or an unavailable account means the item silently is not saved. The failure is now reported through reportSaveFailure and shown by SaveFailureNotice, a FloatingAlert mounted once in each app shell so it stays up after the builder dialog closes. The builder still carries on with the created artifact. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- deferredStore replaces the six hand-written forwarding stores. It forwards each listed method to the store for the settled session, with that store as `this`; the method map's type requires every method. - useSavedWorkStore replaces the four near-identical use*AssociationStoreForMode bodies and backs the reform and flagship report stores too. The test-only resolveStore is gone; the selection tests now check which store is used by what it calls. - The account report store implements createWithId as create (the account assigns IDs), so createWithId is no longer optional and the create mutation needs no casts. - The local delete methods name their callback parameters. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed in, the reforms list fetched every reform's v1 policy through Promise.all, so one 5xx or 429 failed the whole list: "Yours" showed its error state and ReportAdjustPanel aborted its run. Every list load also refetched every v1 policy. - ApiReformStore.findByUser settles each reform separately. A reform whose v1 policy does not load is listed with parametersUnavailable set and no parameters. - The Reforms page labels that card, explains it in the detail view with a "Try again" that reloads the list, and disables run, save, Build and duplicate for it, which would otherwise act on an empty reform. Delete still works. - ReportAdjustPanel never matches such a reform, so it saves the adjusted set as a new reform and runs. - v1 policies never change, so useReformStore fetches each one through the query cache, keyed by country and policy ID. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ssion - AccountAssociationRoutes.writeCountry is the one rule for where a write goes: the item's country when it has account storage, otherwise the store's. The four association stores use it, and so now do the reform store (including where it materializes the v1 policy) and the flagship report store, which wrote in the page's country. - promote's 409 recovery lists and patches in the country it created in, not the page's. - useUserReportById listed saved simulations, policies and households under the report row's own user ID: '' until the row loaded, firing full account list calls under an empty key, and 'anonymous' for a local report read while signed in, caching account rows under the local user. It now lists them for the session's user, once the report row has loaded. (The report-by-ID key itself is unchanged.) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reforms and builder policies share the account's /v2/user-policies rows. Signed out they live in separate stores, so the legacy Policies list and the report builder never showed reforms; signed in, they did. UserPolicyAdapter.isReform (the row carries provenance) now decides, for both lists: the policy store's list leaves reforms out, the reform store lists only reforms. Lookups by v1 policy ID and by association ID are unchanged and still find reform rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The import left out anything another account had imported from this browser. Anyone signed out on the browser can already see those items, so hiding them protected nothing, but it kept a second person from claiming their own signed-out work once someone else had imported it. Each account is now offered the browser's signed-out items it has not imported (or had skipped) itself; readRefsImportedByAnyone is gone. The prompt and account page say these are items saved on this browser while signed out, and the prompt says anyone using the browser signed out can see them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t skips - A write waiting for the session to be restored used to wait forever if the auth provider unmounted first (for example on a country switch, which remounts it). Its waiters now fail with SessionClosedError, which says the save did not happen and to try again. - The import summary gives skips with the Public API's client_ref_conflict reason (the account already holds the item under another country) their own line instead of a bare "could not be saved". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The draft could point at a reform its session could no longer change, and nothing tied it to the session that made it. - The sign-in import points the draft at the account copy of the browser reform it edits (via id_map), so saving after sign-in changes that reform. Saving a draft whose reform is gone from this session's store (deleted, or saved in the other sign-in state) saves it as a new reform instead of failing with no way out. The account store refuses a browser ID before creating a v1 policy for it, and the browser store reports a missing reform as ReformNotFoundError. - The draft is kept with the account that had it signed in, by a fingerprint of its subject (never the subject itself). A page that loads signed out drops a draft left by a session that expired between visits, and a different account signing in drops the previous one's. A session that ends in this page keeps the draft for the person still here; signing out clears it as before. - A token request that fails for any other reason (timeout, network) no longer reads as an ended session: requests report that sign-in could not be reached, and the session stays signed in. - The callback drops ?code&state once handled, so reloading it during the import does not replay a used code. - Before moving anything, the import calls GET /v2/me in the sign-in country, so a first sign-in records that country on the account whichever countries the browser's work is in. - "Save and run" waits while a Save is pending, so the reform is not saved twice, and the latest save error is the one shown. - "Edit the reform" on a report that failed to calculate keeps the saved reform it was run from (useReportRecord reads this session's record in either state), so saving the edit changes that reform rather than adding a copy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…S and UK - A saved reform whose values all match current law can no longer start "View full impact report" (which failed with "Could not start the report"); the button is disabled and the page says why, as Build does. The report page's Recompute likewise waits until some value differs from current law. Bill reports are unchanged: an enacted bill is compared with the law before it. - The account page checks the country before the sign-in state, so a signed-out visitor on ca, ng or il is pointed to the US and UK calculators rather than offered a sign-in Auth0 would refuse. - The clean-slate test also checks the legacy geography key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ed user Signed-out work no longer lives in localStorage and is no longer copied into the account at sign-in. Wherever accounts exist (sign-in configured, US and UK), every reform and report goes through the Public API, one way: - On the first visit the browser gets a random UUID, kept in localStorage (`pe-browser-user-id`) with no expiry. Signed out, requests name it in the `PolicyEngine-Unauthenticated-User` header, and the Public API keeps the work under an unauthenticated user with that ID. The UUID is the credential for that work: it never goes in a URL or log. - Signed out on the US and UK workspace, useV3SavedWork now picks the API stores, scoped to that browser user; the client sends either the session's bearer token or the browser user (V2Credentials). - Signing in calls POST /v2/me/upgrade with the session and the browser user. A first sign-in converts that user into the account, so every saved reform and report stays; an existing account takes over its work. The browser then starts over with a new UUID, so the next person signed out here starts empty; a failed upgrade keeps it for the next sign-in. - The sign-in import, its notice, POST /v2/me/imports and client_ref are removed. MeItem gains user_type, and primary_country may be null. - With sign-in off, and outside the US and UK, work stays in the browser as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Names and titles belong only to the user's records (user_policies and
user_report_associations), never to the shared v1 policy. The v1 policy
route deduplicates on country, change hash and label, so labelling a
policy with a report title or reform name split identical changes into
separate policies, and therefore separate simulations and reports.
createReformPolicy and materializeReformPolicy no longer take a label,
and POST /{country}/policy is sent the changes alone, from report runs,
saved reforms and the bill page's calculation. Identical changes now
share one policy, one pair of simulations and one report per year.
Simulations and reports were already created without labels.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The notice used the legacy calculator's FloatingAlert, which sat at the
legacy header's offset and looked out of place in the v3 workspace. It
is now a v3 panel like the report's calculation-error panel: a white
card with a light border, 12px corners and a soft shadow, floating just
below the v3 top bar; an icon in a tinted circle (teal check when work
moved, warning triangle when it did not); a heading ("Added to your
account" / "Not added to your account yet") over the message; a v3
"Try again" button after a failure; and a ghost dismiss button. Success
is announced as a status, failure as an alert.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"More" sat apart on the right, pushed there with an automatic margin. It now sits in the primary navigation group straight after Build and Reforms, styled like an inactive nav item (same height, padding and weight), and its menu opens from its left edge. The draft chip and the sign-in / user menu stay together on the right. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…new flagship work main gained a second v3 storage path on 13-14 October: a Drizzle/Neon store inside the Next.js app, with no user ids and per-item edit tokens. This branch keeps its own storage instead (the Public API's /v2 routes, as the signed-in account or the browser's unauthenticated user, and the browser's own keys with accounts off), so that path is not merged: calculator-app/src/db (schema, migrations, limits, ownership), the api/reforms and api/reports routes, libs/flagship/ownedItems, the ReformAdapter and reformMetadata types, and their tests stay removed. Everything else from main comes over: - Build: the run bar (year and budget window, population with states and congressional districts, Discard, Save, run), indexing in a pop-up, the editable title, and the new value grid. - A run keeps its reform: "Save and run" reuses a saved reform that sets the same values (findMatchingReform) before saving a new one, and runs on the chosen region with the chosen budget window, starting the report's calculation and its window at once. A failed save still runs nothing. - Reforms: each saved reform lists its reports; in-place edits keep dated values; a saved reform's report runs in the reform's own year. A report record saved through the Public API keeps no year, so the list reads it from the API report. - Report: renaming and population in the adjust panel, "Edit in Build", progress bar, budget window, no-change notice; plus website content. Store interfaces follow main's names: findMine(countryId) and findByApiReportId(apiReportId), with no user id on reforms or records. Names sent to the Public API are clamped to its 255-character limit (and notes to 10,000) with main's storeText helper, so a long bill title cannot fail a save. app.css gets stylelint's empty-line fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 14, 2026
PavelMakarchuk
added a commit
that referenced
this pull request
Oct 14, 2026
- Drop this PR's processed_bills join from billFeed; #1264 owns it (processedBillFor), so a bill gets one stage. Titles now come from the research select, which keeps the edits clear of #1264's lines. - Split the tracker links into BillTrackerLink and TrackerHomeButton, so each import sorts away from #1264's and #1252's import edits. - Economic impacts and the validation drift check read netCost when no stateRevenueImpact is stored, as the headline and the tracker do. - The Reforms header wraps on a narrow screen, so "New reform" shows. - trackerPlace falls back to the upper-case code. - Feed and report test data moves into fixtures. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In the US and UK the budget window asked for with a run was held only in memory, so a reload or another device lost the report's window section. Save its years on the /v2/user-reports record (budget_window_years) and rebuild the run details from the record, window included, from the report's year. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
marked this pull request as ready for review
October 14, 2026 21:29
…new flagship work Brought over from main: comparing a reform with a saved reform (Build's baseline picker, the run, the report's labels and adjust panel), growth settings on provisions, the versioned report schema for stored records and run details (with the unreadable-details state), the report load error, not-found and retry states, phone layouts, the bill filters and the chart fixes. Kept from this branch: the account-backed stores. Account report rows go through the same report schema as browser records; the compared reform is saved as a link (baselineReformId), and its name comes from that reform's own record. Neither the reform nor the baseline policy carries a label. The calculator-app report routes and their tests stay removed, along with the schema helpers that only served them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1253
Summary
Stage 12A of the unified API migration, app side. App v3 (the flagship workspace, US and UK) gets a standard sign-in flow using Auth0 social sign-on, and every v3 reform and report is saved through the Public API: signed in to the account, signed out to this browser's unauthenticated user.
Only app v3 gets accounts. The legacy calculator is unchanged from
mainand stays browser-only. Canada, Nigeria and Israel stay browser-only too, and so does v3 with accounts off. Everything sits behindNEXT_PUBLIC_AUTH_ENABLED, which is off by default.?code&stateonce handled, so a reload does not replay a used code./v2/user-policiesrows withprovenance, each pointing at a v1 policy./v2/user-reportsrows with the v3 fields (title, source note, provisions with their growth settings, validation, the reform it was run from, the saved reform it was compared with, budget-window years), each pointing at a v1 report. The report page rebuilds its header, budget window and comparison from the row, so they survive a reload and open on another device; the comparison's name is read from the linked saved reform, so no name is stored on the report.user_id.pe-browser-user-id) with no expiry and sent asPolicyEngine-Unauthenticated-User. The Public API keeps the work under an unauthenticated user with that ID, created on its first write. The UUID is the credential for that work, so it never goes in a URL or a log.POST /v2/me/upgradewith the session and the browser's user. A first sign-in converts that user into the account (same user, so every saved reform and report stays); an existing account takes over its work. The browser then starts over with a new UUID, so the next person signed out here starts empty. A failed upgrade keeps the UUID (so the next sign-in tries again) and offers "Try again".reforms,pe-flagship-reports,pe-flagship-report-meta), as onmain; saving a reform creates its v1 policy first and keeps the policy ID. Nothing from that storage is copied into the Public API.sur-links, which only ever resolved in the browser that created them. Report URLs use the numeric v1 report ID./[country]/account, in the v3 shell) offers "Download my data" and "Delete my account"; on ca, ng and il it points to the US and UK calculators instead of offering sign-in. The sign-in upgrade notice is a v3 panel under the top bar, and the top bar's "More" menu sits with Build and Reforms.BASE_URLreadsNEXT_PUBLIC_API_URL/VITE_API_URL, defaulting to production, so staging builds talk to the staging API.api/{reforms,reports},calculator-app/src/db,DATABASE_URL, PGlite tests), including the edit-token ownership that landed onmainon 13–14 October (libs/flagship/ownedItems, migration0003_anonymous-ownership). v3 storage is the Public API (or the browser with accounts off), so that path is not merged.mainagain (15 October): comparing a reform with a saved reform (Build's baseline picker, the run, the report's labels and adjust panel), growth settings on provisions, the versioned report schema for stored records and run details (and the "details can't be read" state), report load errors with not-found and retry, phone layouts, the bill filters and the chart fixes. Account rows are read through the same report schema as browser records. The baseline picker lists this session's saved reforms (the account's or this browser's). Neither the reform nor the baseline policy carries a label. The calculator-app report routes, their tests, and the schema helpers that only served them stay removed.main(14 October): the run bar (year and budget window, population with states and congressional districts), indexing in a pop-up, the editable title; "a run keeps its reform" (reuse a saved reform with the same values), reports listed under each saved reform, in-place edits that keep dated values, a saved reform's report run in the reform's own year; the report page's renaming, population and "Edit in Build" in the adjust panel, progress bar, budget window and no-change notice. Store methods followmain's names (findMine(countryId),findByApiReportId(apiReportId)), and names sent to the Public API are clamped to its 255-character limit (notes to 10,000) so a long bill title can't fail a save.@auth0/auth0-spa-js2.27.0,@auth0/auth0-auth-js1.15.0).Environment
Auth0 (
policyengine.uk.auth0.com, custom domainauth.policyengine.orgpending DNS) has two v3 single-page apps, each with Google, Microsoft and GitHub sign-in and no password sign-up:aHhxCvUHwCwCNZekW4yRX6hiGCF9kFYS) for this branch's preview alias (policyengine-calculator-next-git-feat-v3-u-70c7ce-policy-engine.vercel.app) andhttp://localhost:3001;LZBiZVIVG3sLzX66neu2RsE7rUDBDHjX) forhttps://app.policyengine.org.Both allow
<origin>/us/callbackand<origin>/uk/callback, log out to<origin>/usand<origin>/uk, and rotate refresh tokens (30 days absolute, 7 days idle). The audience ishttps://api.policyengine.org/, now with offline access.Vercel (
policyengine-calculator-next):NEXT_PUBLIC_AUTH0_DOMAIN=auth.policyengine.org,NEXT_PUBLIC_AUTH0_CLIENT_IDandNEXT_PUBLIC_AUTH0_AUDIENCE=https://api.policyengine.org/, in Production and in Preview for this branch only. They do nothing while sign-in is off. There is no fixed staging alias (the one custom environment,app-preview, serves another review), so this branch's preview is the staging app.NEXT_PUBLIC_AUTH_ENABLED=trueandNEXT_PUBLIC_API_URL=https://policyengine-api-staging-43j3ckhyaa-uc.a.run.appin Preview for this branch, and redeploy it. Until then the preview stays browser-only, so reviewers can use it.NEXT_PUBLIC_FLAGSHIP_SHELLis not set in Production either.)DATABASE_URL.Known limitations
noneand starts the browser over.Testing
bun install --frozen-lockfilepasses with bun 1.2.21.lint(eslint and stylelint) andtypecheckpass;prettierpasses on every file this PR touches.vitest: 4870 passed, 10 skipped, after the second merge ofmain. One test was updated formain's new adjust-panel labels.typecheckandnext buildpass, including the/[countryId]/accountand/[countryId]/callbackroutes.sur-not-found message and the browser-ID message;Related
🤖 Generated with Claude Code