The labs list layout gains categoryOrder, a bounded allow-list of
category keys (200 entries, 64 characters each, deduplicated, malformed
values dropped on read). GET /api/labs/overview reads the caller's own
layout and answers categories already in that order, so every client
renders them as given. Listed categories come first; keys the data does
not have are ignored; a category the order does not name follows in
the default order (catalog panels, then the person's own by label, then
other). Other left at the end of the order stays last, behind any
category added later; moved anywhere else, it stays there.
Settings > Arrangement > Labs shows a category order card while
categories are on. It lists the overview's categories under their
localised labels, sends the whole order after every move, moves the
cached overview at once and refetches it. The card says how the default
order works. The OpenAPI document carries the new field.
The list layout gains two choices that only the labs list reads:
groupBy (none or category, default none) and groupsOpen (expanded,
flagged or collapsed, default expanded). The resolver keeps a valid
stored value and drops anything else to the default, the PUT merges
both field by field, and the hook exposes a setter for each. A
browser value from before the server column never held them, so the
legacy parse fills them from the defaults.
Add per-user columns for the labs, illness and checkups list presentation
and for preview-feature opt-ins, each with a GET plus a preserve-when-absent
write under /api/settings. The list hook now reads and writes the server
value and carries a browser-stored order up once when the server holds
none, so an existing arrangement follows the person to every device instead
of resetting.