feat(hosts): fixed-rate targets own their cadence — pocketbook declares 30 - #277
Draft
NathanWalker wants to merge 1 commit into
Draft
feat(hosts): fixed-rate targets own their cadence — pocketbook declares 30#277NathanWalker wants to merge 1 commit into
NathanWalker wants to merge 1 commit into
Conversation
…es 30 TargetProfile.tickHz names the rate a fixed-cadence host drives; the resolver copies it into plan.target and plan builds bake it (a conflicting --hz errors; rate-less targets keep their plan shape, hash and --hz flow). hosts/pocketbook declares 30 before mount and derives its wall step from the same constant, so ms animations run wall-true instead of half speed. The widget examples wire one TICK_HZ constant through WidgetConfig.tick_hz and the surface declaration so the two cadences cannot drift. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The migration deferral from #257: the two in-tree off-60 hosts weren't using the mechanism built for them, and the repo had three cadence notions with no single owner. This gives fixed cadences one owner — the target profile — and migrates both flagged hosts.
The ownership chain
TargetProfile.tickHz(new, optional) names the rate a fixed-cadence stock host drives. From there:plan.target.tickHz(omitted — notundefined— for rate-less targets, so their plan shape and hash are untouched; the PSP plan pin still passes verbatim).pocket compile --target pocketbooknow bakes 30 with no flag); an explicitly conflicting--hzerrors:--hz=60 conflicts with the pocketbook plan rate 30 — the target's host drives that rate. Rate-less plans (ios-dev's per-run--hzstaging) keep today's flag flow.hosts/pocketbookdeclaresTICK_HZ = 30before mount (ensure!d, not discarded) and derives its wall step from the same constant —Duration::from_micros(1_000_000 / TICK_HZ), replacing theTICK_MS = 33approximation that ran ~1% fast.So bundle and host pair by construction, and the pairing invariant enforces it: the profile is the only place the number 30 lives on the TS side, mirrored by one Rust const the way
HOST_ID/HOST_ABIalready are.What this changes on a PocketBook
Every ms-based animation ran at half wall-clock speed on the device (core believed 60, host ticked ~30). Declared, they run wall-true. That is the observable-timing churn flagged in review — no committed tape records a pocketbook run today, so nothing in-tree churns; the change lands on the device, and the hardware checklist in
docs/IMPLEMENTATION.mdcovers re-validating there. Pairing is enforced both ways: an old 60-baked bundle refuses the new host loudly, a 30-baked bundle refuses everything else (native target mismatch/tick-rate mismatch— both reproduced below).pocket-widget
No in-tree widget runs off-60, so the hazard was the unwired seam:
WidgetConfig.tick_hzwas a free knob the embedded realm never heard about. Both examples now thread oneTICK_HZconstant through the config and the surface declaration (ensure!d), and thetick_hzdoc states the duty — a copy-pasted boot stays paired when someone turns the knob.uihostdeliberately stays undeclared: it is the minimal identity-less host, and absent__tickHzmeans the 60 it drives.Verification
bun pocket compile --target pocketbook --manifest apps/hero/pocket.json→ plan carriestarget: { id: pocketbook, hostAbi: 5, tickHz: 30 }, build log reads30Hz, target=pocketbook;--hz=30accepted,--hz=60errors as above.--hz=30hero throughrender_herowithPOCKET_TICK_HZ=30: 180 deterministic non-blank frames; the same bundle on an undeclared host dies with the 30-vs-60 mismatch. The plan-built pocketbook bundle on a non-pocketbook host dies withnative target mismatch (bundle=pocketbook, host=desktop).cargo checkclean forpocketbook-host(pluscargo clippy, keeping the README's clippy-clean claim true),pocket-widget,note-widget,pocket-stage.bun run test11/11 stages green (38.4 s);bunx tsc --noEmitclean;bun tests/contract.tsgreen. New pins: the registry test asserts pocketbook 30 / everyone else rate-less; a resolver test asserts the pocketbook plan carries the rate and its hash verifies.Series context: #275 (audio formula) and #276 (wasm export + sim coverage) are the sibling #257 follow-ups; all three are independent of each other.
🤖 Generated with Claude Code