Second batch from the staging UX audit (BUG-248..253).
- css: expose the 32 palette tokens through @theme. Seven utilities
including text-ink, text-danger and text-warning compiled to no CSS
at all, so 30 call sites had been silently inert (BUG-248)
- chat: move the composer into its own component behind a draft store,
so a keystroke no longer re-renders a 2723-line component, and
persist the draft across reloads (BUG-249)
- chat: load gsap, react-markdown and thinking-orbs on demand. First
Load JS for / drops 549.5 kB to 476.3 kB gzipped (BUG-250)
- chat: route the five in-app destinations through router.push, and
keep the five auth redirects and the bootstrap retry as hard loads
on purpose (BUG-251)
- a11y: announce reply completion, and move the live region out of the
aria-busy subtree that was likely suppressing even the start
announcement (BUG-252)
- docs: give the 27 collided bug ids unique numbers and repair their
inbound references; require search rather than a full read of a
3690-line file (BUG-253)
Verified: tsc, eslint, next build, and 1592 assertions across the 199
non-database test files.
Co-authored-by: Cursor <cursoragent@cursor.com>
Framework-level UX fixes found while auditing staging (BUG-216..220).
- chat: route 44 previously discarded composer notices to sonner with
dedupe, so recovery, cancel and archive feedback is actually visible
(BUG-216)
- chat: anchor stream auto-scroll to bottom proximity and add a
jump-to-latest control, so reading history is no longer interrupted
on every token (BUG-218)
- reports: replace the silent 120s poll cutoff with an explicit
timed-out state, an 8m budget, stepped backoff and an elapsed
counter (BUG-217)
- reports: pause polling while the tab is hidden, via a shared hook
- app: add root error, global-error and not-found boundaries (BUG-219)
- admin: add antd SSR style extraction and the React 19 render adapter,
and move admin-only css out of the global stylesheet (BUG-220)
- membership: run bootstrap fetches concurrently and pause payment
polling while hidden
- build: configure optimizePackageImports
Verified on top of 2d370f2e: tsc, eslint, next build, and the related
frontend contract suites.
Co-authored-by: Cursor <cursoragent@cursor.com>
The sidebar contract read a selector with indexOf, so it returned whichever
rule appeared earliest in the file. A responsive override added above the base
rule made the gate report a missing min-height that was never removed, which
blocked staging on a change that was correct.
Share one helper that strips comments, parses rule by rule, accepts a whole
group as the query, and returns the declarations of every matching rule. The
union also makes a negative assertion mean no rule may declare the property,
which is what these contracts intend.
The helper was duplicated in two files and had no tests of its own; it now has
regressions for each way it read the wrong block.
Co-authored-by: Cursor <cursoragent@cursor.com>
Every workflow fault except abort and timeout collapsed into the single
calculation_failed code, and the upstream message was discarded, so a failing
run left no evidence of whether the API rejected the call or returned a payload
that missed the response contract.
Classify failures into a closed vocabulary carried on ConsultationWorkflowError
and record it as the failureCode of the runtime step. The observability tool
call schema gains one controlled optional field; upstream error text stays out
of logs, as that contract requires. Forward request_id to the API so a run can
be aligned with its access log.
Build public receipts from an explicit allowlist. The internal failure code
must not reach the client contract, whose step schema is strict and would
otherwise reject a successful run.
Co-authored-by: Cursor <cursoragent@cursor.com>
The runtime contract gated on total consultation tool attempts, so a single
transient calculation failure raised the counter past one and made the run
unrecoverable even after a later attempt succeeded. The already-computed chart
was discarded and the request ended as runtime_contract_incomplete.
Count only successful workflow executions against the single-calculation
boundary. Failed attempts stay in the attempt counter for observability. The
request-scoped cache still retains the successful promise, so a request can
never run more than one billable calculation.
Also record the staging-first branch delivery convention in AGENTS.md.
Co-authored-by: Cursor <cursoragent@cursor.com>
Hide the dead composer during birth-time intake, replace internal
copy with user-facing hints, and keep short-screen login, location
search, and session history reachable on phones.
The staging host currently has .state/deployed-revision unreadable by the
deploy user, so the forward-only revision check failed with 'Permission
denied' before it could compare revisions. Treat an unreadable state file
like a missing one and discover the running revision from the web
container's GITHUB_SHA, in both the workflow step and the server-side
deploy/migration scripts.