Add nyan_filler: on-device Nyan Cat dark-filler - #17
Conversation
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Review found the unconditional client.clear(APP) at main() startup fired a real device write even under --dry-run, contradicting the plan's Step 6 "no device writes" acceptance criterion for dry-run mode. Move it inside the same guard that already gated the self-healing asset upload so both startup device writes are skipped together in dry-run.
Fix three factual inaccuracies identified in post-review: 1. --once --dry-run makes zero device calls; fix test section to recommend --once 2. Asset uploads on EVERY process start, not conditionally; fix startup section 3. poll_seconds controls host re-assertion, not animation frame rate; fix config table All fixes verified against main.py code. Tests still green (369 passed).
Fix four more accuracy issues identified in second review round: 1. Design section: clarify upload happens on EVERY non-dry-run process start, not just first run 2. Design section: reword rebuild guidance to clarify re-uploads are unconditional 3. Test output example: use real DrawResult value 'drawn' instead of 'ACCEPTED' 4. Add quiet_hours caveat to test section (default window suppresses draw) All fixes verified against main.py and src/busybar/client.py. Tests still green (369 passed).
…t, quiet_hours validation) Applies all four must-fix items from the final whole-branch review: gate per-poll INFO logging behind a change/heartbeat helper (mirrors calendar_countdown's should_log_info), fix the broken `python tools/build_nyan_anim.py` invocation to `-m tools.build_nyan_anim` in both the tool's docstring and main.py's runtime warning, make test_nyan_filler_defaults hermetic against a real repo-root config.toml, and fail fast with a clean error (not a launchd crash-loop) on a malformed quiet_hours at startup. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1d10a9845c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The .anim upload was a one-shot at startup guarded by --dry-run; if the device was transiently unreachable at that instant, upload_asset returned False, nothing retried it, and every subsequent draw for the life of the process referenced an asset that was never uploaded (it worked only when the asset happened to already be on the device from a prior run). Move the upload into run_once behind an `asset_uploaded` latch: attempt it on each active poll until it succeeds once, then never again — no per-poll uploads in steady state. In the in-scope transient-unreachable case the retries are naturally spaced by main()'s exponential UNREACHABLE backoff. A locally missing build artifact is warned once and skipped (polling can't fix it). Extend FakeClient with upload_asset coverage and refresh the README section that previously said the upload never happens during polling. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 39a01bc657
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Robustness fix folded in: self-healing asset upload (
|
|
FYI for anyone with |
# Conflicts: # tests/test_config.py
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3867618581
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…pload retries - anim_encoder: cap the per-frame duration byte at 255, splitting runs of 256+ identical frames into chunks (was a ValueError on serialize). - ensure_asset_uploaded: exponential backoff (5s->x2->300s cap) between failed upload attempts, so a persistent non-200 (device reachable for draws but rejecting the upload) no longer re-POSTs ~76KB every poll; transient failures still retry until they latch. Updated the retry test to advance the clock past each backoff window. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dd05ba45a8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| ensure_asset_uploaded(client, state) # retries until it lands once; then a no-op | ||
| result = client.draw(APP, elements, priority=PRIORITY_FILLER) |
There was a problem hiding this comment.
Avoid drawing until the asset is available
On a fresh device where the asset is absent and the upload is currently throttled, rejected, or skipped because the local file is missing, ensure_asset_uploaded() returns without setting asset_uploaded, but the draw is still submitted every poll. The device then rejects the missing-asset reference and BusyBarClient.draw() logs a warning each time—up to roughly 86,400 warnings per day at the default interval—so the new upload backoff does not prevent the persistent log/request flood. Skip the draw until the upload succeeds (and likewise while the local artifact is missing).
Useful? React with 👍 / 👎.
What & why
A third integration,
nyan_filler, that fills the BUSY Bar's panel with an on-device Nyan Cat animation whenever it would otherwise be black — the CI overlay's dwell gaps and idle time — except during quiet hours. This closes the "blank screen during the CI cycle" gap.How it behaves (verified on-device, fw 1.1.1)
PRIORITY_FILLER = 5— above the empty/stub panel (priority 0), below built-in apps (10) and every other tier. Confirmed on hardware: fills a black gap (DRAWN), and is rejected (409) by a built-in app@10 and by the CI/calendar tier@21 — so it never overrides a built-in app and yields to everything real..anim(bicycle0) the device self-loops; host cost is ~1 tiny re-assert draw per poll (no per-frame pushing). The asset is generated by an in-repo encoder ported from the firmware's ownseq2anim.ts(tools/anim_encoder.py) and committed atassets/nyan/nyan_72x16.anim.00:00–07:00(configurable;""disables). Per-poll INFO logging is change-gated + heartbeat (mirrorscalendar_countdown) so a 1s poller doesn't flood the log.--dry-runmakes zero device writes.Design & rationale
Four on-device spikes (native
.animrenders; redraw continues the loop; priority floor is 0; the ported encoder produces a device-renderable file) are recorded in the spec:docs/superpowers/specs/2026-08-06-nyan-filler-design.md. Plan:docs/superpowers/plans/2026-08-06-nyan-filler.md.Testing
upload_asset).--onceuploads + draws.Notes
tools/; the shipped integration is stdlib +requests).config.tomluntracked.🤖 Generated with Claude Code