Skip to content

fix: re-apply the theme after missed boundaries - #24

Merged
clappingmonkey merged 1 commit into
mainfrom
fix/missed-boundaries
Sep 27, 2026
Merged

clappingmonkey merged 1 commit into
mainfrom
fix/missed-boundaries

Conversation

@clappingmonkey

Copy link
Copy Markdown
Owner

What & why

Fixes cases where the theme didn't switch, or switched late (audit item H3):

  • Sleep across two boundaries: the period on wake matches the one before sleep, so a manual /theme from before sleep was kept, e.g. sleeping from evening until the next evening.
  • Long checkIntervalMs: switches waited for the next tick. At 24h the theme never switched, and at 13h some periods were skipped entirely.

Changes:

  • New exported pure helper nextPeriodChange(from, cfg, horizonMs). It returns the exact next day/night change by checking only the instants where one can happen: 15-minute UTC marks in fixed mode, and each solar day's start, sunrise and sunset in solar mode. So even very short periods near the polar circle are found (for example a 2-minute night at 66.34°N).
  • tui remembers when it last checked the period. It re-applies the theme if any boundary was crossed since then, even when the period now looks unchanged (looking back up to 400 days).
  • A one-shot timer fires at the next boundary, so switches happen on time whatever checkIntervalMs is. The interval stays as a fallback. The timer is cleared on abort/dispose.
  • Failed or not-ready applies still don't advance state, so they are retried.
  • README: "How it behaves" and the checkIntervalMs row are updated (this also fixes the README part of audit item L5).

Behavior impact

  • Theme-switching logic (periodFor, boundaries, gentle override)
  • Plugin options (dayTheme, nightTheme, dayStartHour, nightStartHour,
    checkIntervalMs, toast) — README options table updated
  • Lifecycle / timer / toast behavior
  • Packaging (package.json exports, files, published contents)
  • No user-facing behavior change

After waking up past a boundary, a manual /theme is now replaced by the configured theme for the current period. Within a period it is still kept.

Testing

  • npm run typecheck passes
  • npm test passes: 56 tests (11 new nextPeriodChange unit tests, 7 new tui tests). Also passes under TZ set to UTC, Europe/London, America/St_Johns, Australia/Lord_Howe, Asia/Kathmandu, Pacific/Chatham and America/New_York.
  • Manually verified in opencode (if behavior changed): not done

Extra checks:

  • Brute-force comparison of nextPeriodChange against a 30-second scan for 246 configs over all of 2026: 0 mismatches.
  • Mutation checks: removing the missed-boundary check or the boundary timer, or advancing state on a failed apply, each fails a test.

Checklist

  • PR title follows Conventional Commits
    (enforced by the PR Title check; drives the release-please version bump)
  • Defaults still work with zero config
  • Docs updated if behavior/config changed
  • No secrets or credentials introduced

The theme could stay wrong after the machine slept across two boundaries, and a long checkIntervalMs delayed or skipped switches. A new exact helper, nextPeriodChange, finds the next day/night change; tui uses it to detect crossings since the last check and to arm a one-shot timer at the next boundary.
@clappingmonkey
clappingmonkey merged commit 8405957 into main Sep 27, 2026
3 checks passed
@clappingmonkey
clappingmonkey deleted the fix/missed-boundaries branch September 27, 2026 11:07
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