Fixed
-
The embedded console stamped a theme the reader never chose.
ui.html
calledapplyTheme(currentTheme())on load, and that wrotelocalStorage, so
simply opening the console recorded an explicit preference — which then
outranked the operating system on every later visit, on the console and on
the marketing site, since the two deliberately share theor-themekey. The
site had the identical bug insite.js.A stored theme and an accidental one were indistinguishable after the fact, so
the key could not be repaired in place. Both surfaces now write
or-theme-setonly on a click, and an unmarked value is treated as the
accident it probably was: the machine's preference wins. A reader who did
genuinely choose pays one click, once.Verified in a browser across six states — a legacy stored dark on a light
machine now resolves light, while an explicitly chosen dark still resolves
dark. -
The console's theme is now applied before first paint and its sun/moon
glyph comes from CSS on[data-theme]rather than a deferredinnerHTML
swap, so a reader on a light machine no longer sees the wrong glyph until
script runs. -
Light-theme nav links measured 3.54:1 against a real backdrop. The header
is 82% paper over a blur and the code panels are fixed-dark in both themes, so
with a panel scrolled under the glass the effective ground is
rgb(200,199,194). Against flat--paperthe same token is 5.2:1, which is
whycheck-contrast— which reads tokens, not composited pixels — was green
throughout. Now--text-2: 6.68:1 worst case.
Verify before you run this
curl -fsSLO https://raw.githubusercontent.com/vul-os/openrate/v0.1.8/scripts/verify.sh
bash verify.sh --tag v0.1.8 --attest openrate_0.1.8_source.zipverify.sh fetches SHA256SUMS, looks up the exact entry for the
asset and compares digests. It exits non-zero, with a distinct
diagnostic, on a missing or malformed manifest, a missing entry, a
truncated download or a digest mismatch. There is no skip path and a
missing SHA256SUMS is never treated as "nothing to check".
--attest additionally checks the sigstore build provenance (needs
the gh CLI); without it, provenance is NOT checked and the script
says so rather than letting a pass imply more than it checked.
Full Changelog: v0.1.7...v0.1.8