Skip to content

Offer the simulator one input per metric, not one per source - #26

Merged
freethinkel merged 2 commits into
mainfrom
fmc(sim-metrics)
Aug 11, 2026
Merged

Offer the simulator one input per metric, not one per source#26
freethinkel merged 2 commits into
mainfrom
fmc(sim-metrics)

Conversation

@freethinkel

Copy link
Copy Markdown
Owner

The Simulator panel listed one input per data source, and the firmware answers many ids out of one
metric — steps alone covers eight (0x19, 0x25, 0x26, 0x49, 0x6a, 0x6c, 0x6f, 0x82, all
Number(sim.steps) in idValue). So Combo showed a Steps field, a Steps goal field, and
three more inputs — steps (slot) (0x26), (0x49), (0x6c) — for the same number. Worse, a value
typed in one of those wins over the field above (idValue reads sim.overrides[id] first) with
nothing in the UI saying so.

On top of that the grid was a fixed list of eleven metrics regardless of the document: Combo has no
AQI, temperature or distance widget and got fields for all three.

After

The grid is derived from what the open document reads, each metric with its goal beside it. Combo
goes from eleven fields to three:

before after
Steps · HR · Battery · Calories · Distance · Temp · AQI · Stand hours · Steps goal · Cal goal · Stand goal, then 9 per-id rows Steps · Steps goal · Battery, then a folded per-source overrides

The per-id inputs are still there — they are the only way to drive two widgets on one metric apart,
or to pin a hand — but inside a <details> whose summary counts how many are set, so a shadowing
override is visible instead of silent.

Where the mapping lives

Which metric an id reads was implicit in idValue's switch and duplicated as hint strings in the
panel ("0x19, 0x26, 0x49, 0x6a, 0x6c"). It is now the ID_METRIC table, which idValue itself
reads for every source that is a plain passthrough; the derived ones (distance's km/mi, integer and
fraction splits) still compute in the switch and are listed only so the panel can group them.
tests/sim-sources.test.ts asserts per id that the two agree — each mapped id must move when, and
only when, the metric the panel files it under moves.

Also

/max was the widget's declared max (meta.max — a hand's 60 positions, a number's digit cap),
not the metric's range, which is why the panel offered "day of month /60". It reads max 60
now, with a title saying whose max it is.

Verification

pnpm check 0 errors, pnpm lint clean, oxfmt --check clean, 185 tests pass (24 new). Checked in
a real browser against Combo: three fields, the fold opens to the nine sources, typing 999 into
steps (slot) (0x26) flips the summary to "per-source overrides — 1 set".

(The first commit is the same format:check fix as #25frame-thumb.svelte is unformatted on
main, so CI is red there for both branches until either lands.)

🤖 Generated with Claude Code

https://claude.ai/code/session_01QLHPEnYV5UMkne4WBTCk5s

freethinkel and others added 2 commits August 10, 2026 14:24
Pre-existing on main — the button's attributes sit on one over-long line and
`oxfmt --check` has been failing on it, which is why CI is red here too.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLHPEnYV5UMkne4WBTCk5s
The firmware answers eight different source ids out of `steps` alone, and the
panel listed all of them: a face with a steps ring showed a "Steps" field, a
"Steps goal" field, and three more inputs (0x26, 0x49, 0x6c) that all stand for
the same number — with whichever was typed last silently winning, since idValue
reads an override before anything else.

The grid is now built from the metrics the open document actually reads, with
its goal beside it: Combo drops from eleven fields to three, Steps / Steps goal
/ Battery. The per-id inputs are still there — they are the only way to drive
two widgets on one metric apart, or to pin a hand — but folded into a <details>
that says how many are set, so an override can't shadow a field unnoticed.

Which metric each id reads was implicit in idValue's switch and duplicated as
hint strings in the panel; it is now the ID_METRIC table, which idValue reads
for every source that is a plain passthrough (the derived ones — distance's
km/mi, integer and fraction splits — still compute in the switch, and are listed
so the panel can group them). A test asserts the two agree, per id.

Also: the /max hint was the WIDGET's declared max, not the metric's range, which
is why the panel offered "day of month /60". It reads "max 60" now, with a title
saying whose max it is.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLHPEnYV5UMkne4WBTCk5s
@freethinkel
freethinkel merged commit 5e78952 into main Aug 11, 2026
2 checks passed
@freethinkel
freethinkel deleted the fmc(sim-metrics) branch August 11, 2026 20:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant