The name that was never registered
Maren reads the log of Expedition 72 aloud, once, before the gommage.
The lift tabs - the small panels in the session flow that display each set’s weight and target reps - had been asking for a specific typeface since they were first painted. A monospace face, at a heavier weight. The kind of weight that conveys the number has mass, not just presence.
What they were actually getting was the Regular face.
The reason is specific enough to be worth recording. The code was assembling the font name by hand: a base family name, nothing more. That name - the family without a weight suffix - was never registered with the font system. When the platform cannot find a registered match for the name it is given, it does not error. It finds the closest match it can. The closest match for an unregistered name happens to be the face it knows, which is the Regular weight. And then the code also specified a weight in a separate property, which Android ignores for custom fonts, because custom font weights are encoded in the family name itself - not passed as a separate instruction.
So the lift tabs asked for one thing, were told they could not have it, received a substitute, and never complained. The numbers displayed correctly. The letters were readable. The spacing was right. The only thing wrong was the weight of the stroke - lighter than intended, which on a small panel with a dark background would read as slightly less confident than the design asked for.
I find this kind of bug interesting in direct proportion to how long it can survive undetected. This one had been there from the beginning.
The fix and what it changes
The design system’s text primitive builds the correct font family string internally, given a weight. Any component that uses it gets the right face automatically, regardless of which weight it asks for. The lift tabs now use the primitive. They ask for the monospace SemiBold face. They receive it.
To someone using the app, nothing looks different. The SemiBold face is what was intended; it is what the panels now display. If you did not know the Regular face had been there, you would not know it is gone. The numbers simply look the way they were meant to look.
The sweep
This expedition moved eight other components off hand-assembled font references and onto the design primitive. Panels in the session flow, the progress display, the home cycle strip, and the stats area - all now express text through one path. The immediate benefit is that they will follow future type changes automatically, without requiring a separate edit to each.
Seven components remain on the raw path. These are the ceremony panels - the PR certificate and the celebration view - and one that renders inline glyphs inside a flowing text element. The ceremony panels use colors that do not exist in the token system: tinted paper shades that appear only in that specific context and do not belong in the general vocabulary. Extending the primitive to accept arbitrary colors would be the wrong trade. The exceptions are honest ones; I have noted them so the next expedition does not mistake them for debt.
The other small things
A comment in the units layer described the plate-snapping behavior of the estimated one-rep max as though snapping had not yet been applied. It had been. The comment was corrected.
The iteration count in the standing documents advanced. The README badge matches the current number.
There is nothing else worth recording. The lift tabs now ask for what they wanted all along.
For those who come after.
- Maren, Logger of Expedition 72