## What this does Rounds out the theme work behind the existing `hasThemeSwitcher` flag. **Two new themes.** Black and White sit alongside Dark and Light. They inherit their neighbour's whole token set and only pin their surfaces flat, so sections are separated by grid lines rather than layered fills. **`System` is now configurable at both ends.** You choose which theme the OS light setting lands on (Light or White) and which the dark setting lands on (Dark or Black). **Two accessibility toggles.** - *Stronger colors* — swaps tinted status chips for solid fills, drops decorative icon accents to monochrome, and darkens chart series that didn't clear 3:1 on a white plot. - *Underline links* — underlines body-text links, so an underline always means the preference is on rather than being a hover style. **Contrast slider.** Stores a 0–100 position within the active theme's own range rather than a shared scale, so 35% stays 35% when you switch themes. Each theme maps it in CSS, which keeps `system` working before hydration. **Appearance in the account popover.** A submenu listing the themes with a check against the current one, plus a link through to the full set on your profile. Picking one applies immediately rather than waiting for the write to round-trip. **Profile page.** Each row now saves on its own — no submit button. Name and email show their value inline with an edit button; the email row is read-only when an identity provider owns the address. **A `/storybook/colors` audit page.** Renders every colour-carrying pattern in the app once per theme plus once under Stronger colors, and measures contrast ratios off the live DOM rather than a hard-coded table, so it can't go stale. --- ## Demo https://github.com/user-attachments/assets/d56cd4d8-719f-4ec5-a990-e04cdb98def1 --- ## Compatibility The stored preference shape is unchanged (`version: "1"`), and the four new fields are all optional. The retired `classic` theme falls back to Dark, whose palette at contrast 0 is what Classic shipped. One deliberate change worth knowing: the default contrast moves from 50 to 0, so existing users who never touched the slider will see slightly less contrast than before. That's what makes 0 mean "the base palette". --- ## Testing Switched between every theme from both the account popover and the profile page, in the expanded and collapsed rail, checking `data-theme` follows and survives a reload. Dragged the contrast slider in each theme and confirmed the percentage label tracks the handle and resnaps if a save fails. Checked both accessibility toggles across the `/storybook/colors` page, which is also where the contrast ratios were read from. Confirmed the Appearance entry stays hidden for a non-admin while the flag is off. <!-- conductor-workspace-link --> --- [Open workspace in Conductor](https://app.conductor.build/workspace/fee50611-7623-4422-bada-ed1cba317ed1) --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Server Changes
This directory tracks changes to server-only components (webapp, supervisor, etc.) that are not captured by changesets. Changesets only track published npm packages — server changes would otherwise go undocumented.
When to add a file
These entries are user-facing release notes, not a catalog of every change. The test is "would a user or customer care about this change?", not "did I touch a server app?". Add one only when a server-only change is something a user would notice, act on, or want to hear about (a feature, a bug fix they could have hit, a behavior or performance change they would feel). Skip it for internal-only or admin-only changes, refactors, test-only changes, chores, and performance tuning with no user-visible effect. Anyone who wants the exact history reads the commits. When in doubt, ask a maintainer rather than adding a note by default.
Server-only PRs: If your PR only changes apps/webapp/, apps/supervisor/, or other server components (and does NOT change anything in packages/) AND the change is user-facing, add a .server-changes/ file.
Mixed PRs (both packages and server): the changeset covers it, so no .server-changes/ file is needed. If the package change is internal and needs no changeset but the server change is user-facing, add a .server-changes/ file for it.
Package-only PRs: Just add a changeset as usual, when the change is user-facing.
File format
Create a markdown file with a descriptive name:
.server-changes/fix-batch-queue-stalls.md
With this format:
---
area: webapp
type: fix
---
Speed up batch queue processing by removing stalls and fixing retry race
Fields
- area (required):
webapp|supervisor - type (required):
feature|fix|improvement|breaking
Description
The body text (below the frontmatter) is a one-line description of the change. Keep it concise — it will appear in release notes.
Writing guidance
These entries are public-facing - they ship verbatim in user-visible release notes. A few rules to keep them clean:
- Write for the user, not the reviewer. Lead with what the user notices or has to do. If a reader who doesn't know the codebase can't tell what changed for them, rewrite it.
- One sentence is usually enough. The body is the bullet in the changelog. If you need a paragraph, you're probably describing the implementation rather than the change.
- Describe behavior, not implementation. Skip internal scopes, middleware names, library specifics, framework internals. Users care about what's different for them, not how it's wired.
- Never name internal tools or infra. Observability stacks, internal services, infra components, monitoring backends, CI surfaces, AWS specifics - none of these belong in user-facing notes.
Before / after:
- ❌ "The image verification step now parses the manifest's layer media types and returns a new result the finalizer rejects." (describes the wiring; a user can't act on it)
- ✅ "Deploying with an outdated CLI could produce an image that fails to start on every run. These deploys are now stopped before going live, with a message asking you to upgrade the CLI and re-deploy." (what the user sees and does)
Lifecycle
- Engineer adds a
.server-changes/file in their PR - Files accumulate on
mainas PRs merge - The changeset release PR includes these in its summary
- After the release merges, CI cleans up the consumed files
Examples
New feature:
---
area: webapp
type: feature
---
TRQL query language and the Query page
Bug fix:
---
area: webapp
type: fix
---
Fix schedule limit counting for orgs with custom limits
Improvement:
---
area: webapp
type: improvement
---
Use the replica for API auth queries to reduce primary load