Design: the colour function takes a background, not a scheme
ui-guidelines-52 corrected the signature after Docs turned out to need highlights on paper white in every theme, including dark ones — a scheme parameter can only mean "resolve against the theme's surface", which is wrong for any caller whose content does not sit on that surface. Better for Sheets too. A cell's real background is not always the sheet surface: conditional formatting paints under a user fill, and selected or frozen cells sit on something else again. We pass what the cell actually sits on, and the contrast gate asserts against that exact colour. Also records the second entry point — distinguishable-colour allocation — and that Sheets is a caller of it. Presence cursors need collaborators mutually distinguishable, which is the same problem as Docs' comment author colours, and not the same guarantee as contrast-correctness.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01APtNStXDZ5H2fAc1ZuGqtS
1 file changed,
+30
−3
docs/superpowers/specs/2026-08-30-sheets-design.md+30 −3
diff --git a/docs/superpowers/specs/2026-08-30-sheets-design.md b/docs/superpowers/specs/2026-08-30-sheets-design.md| index 072e6e9..5759b05 100644 |
| --- a/docs/superpowers/specs/2026-08-30-sheets-design.md |
| +++ b/docs/superpowers/specs/2026-08-30-sheets-design.md |
| @@ -411,11 +411,38 @@ XLSX import→export round-trips losslessly, and is dropped the moment a user |
| re-picks that cell (ruling 8). |
| **ui-guidelines-52 owns the implementation**, in `ui`, as a pure function over |
| -a bounded offered hue set, callable outside a render. We are one of three |
| -callers (cell fill; Docs' text highlight; Docs' comment author colours). |
| +a bounded offered hue set, callable outside a render. |
| + |
| +**The signature takes a literal background, not a scheme** (corrected by |
| +ui-guidelines-52, 2026-08-30, after Docs turned out to need highlights on |
| +paper white in every theme including dark ones): |
| + |
| +``` |
| +(hue, chroma, background) → {fill, on-fill} |
| +``` |
| + |
| +A `scheme` parameter could only ever mean "resolve against the theme's |
| +surface token", which is wrong for any caller whose content does not sit on |
| +that surface. Passing the background makes the function honest about what it |
| +measures against, and it is strictly better for us too: a cell's real |
| +background is not always the sheet's surface — conditional formatting can |
| +paint under a user fill, and a selected or frozen cell sits on something |
| +else again. We pass what the cell actually sits on and the gate asserts the |
| +pair against that exact colour. |
| + |
| +**Second entry point: distinguishable-colour allocation.** Contrast- |
| +correctness and perceptual separation are different guarantees, so allocation |
| +is its own function — hash a stable identity into the bounded hue set with a |
| +separation guarantee, then resolve each through the pair function above. |
| +**Sheets is a caller**, not just Docs: presence cursors (§7) need collaborators |
| +mutually distinguishable, which is the identical problem to their comment |
| +author colours. If conditional formatting later wants "N distinguishable |
| +fills" — a categorical scale — that is this entry point, not N calls to the |
| +first one. |
| **Until it ships: a deliberately crippled shim.** A hardcoded table of six to |
| -eight intents with hand-computed pairs, behind that exact signature, gated by |
| +eight intents with hand-computed pairs, behind the corrected signature above |
| +— never the scheme-shaped one, so the swap stays a deletion — gated by |
| a contrast test that **copies rastrillo's arithmetic verbatim** — not merely |
| models it, or the two gates diverge by a rounding decision and swapping the |
| table changes the test's meaning silently. The file carries a header comment |