Test Notification Thresholds through tick() behind an injected notification seam - #41
Merged
Merged
Conversation
WorkdayManager no longer reaches for NotificationManager.shared. It takes a WorkdayNotificationSending dependency through init, defaulting to the production adapter, the same way it receives its prompt presenter. The new-day notice is pinned through a recording test adapter. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WFc8P7zoT4V7GQaqwegkcm
Describe the milestone through WorkdayManager's interface only: it notifies once when enabled, still prompts to end the day when notifications are disabled, is recorded in the Daily Log across a reload, yields to a pause or a pending Idle Period before the prompt appears, and waits for recent activity. The recording prompt adapter is shared so it can record the end-of-day prompt. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WFc8P7zoT4V7GQaqwegkcm
Normal and critical each notify once, stay silent when notifications are disabled, and survive a reload from the same store. Pin the agreed edge cases where Net Work Time jumps past several Thresholds at once: critical is notified instead of normal, and critical follows the milestone one tick later. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WFc8P7zoT4V7GQaqwegkcm
A Workday's notified Notification Thresholds are a Set<NotificationThreshold> instead of free strings that only matched the notification identifiers by coincidence; ThresholdType now derives its identifier from the same type. NotificationThreshold is string-backed, so Daily Logs encode the same strings as before, previous Daily Logs still count as already notified, and an unknown value is kept rather than making the file unreadable. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WFc8P7zoT4V7GQaqwegkcm
When Net Work Time jumps past several Notification Thresholds at once, only the highest one is notified. The lower Thresholds crossed in the same jump are recorded as notified, so they no longer follow one tick later or after a reload. The milestone records them even when notifications are disabled. Crossing Thresholds one after another still notifies each once. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WFc8P7zoT4V7GQaqwegkcm
- Rename NotificationThreshold to NotifiedThreshold so it no longer reads as the configured NotificationThresholds. - The WorkdayNotificationSending seam speaks in NotifiedThreshold plus hours; NotificationManager.ThresholdType is gone, leaving one list of Threshold kinds. The recording adapter records the typed kind. - Notification tests share one fixture with recording prompts, an isolated widget store and main-queue draining, and release their manager in tearDown. The previous-version Daily Log test moves next to the other threshold tests. - The disabled-notifications test gains a positive control, and small wording and decoder duplication fixes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WFc8P7zoT4V7GQaqwegkcm
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WFc8P7zoT4V7GQaqwegkcm
Resolve the XcodeGen project conflict by regenerating it from project.yml, so it contains both the shared Workday appearance files and the notification seam files. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WFc8P7zoT4V7GQaqwegkcm
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.
What does this PR do?
Makes the Notification Threshold policy testable through
WorkdayManager's interface and fixes how thresholds are reported when Net Work Time jumps past several at once.WorkdayManagersends threshold and new-day notifications through an injectedWorkdayNotificationSending, defaulting toNotificationManager.shared. Tests use a recording adapter.tick(): tests move the ManualClock forward and calltick()to cover:NotifiedThresholdtype instead of free strings. The Daily Log JSON is unchanged, old logs decode, and unknown values are preserved..scratch/added to.gitignore.How to test?
xcodebuild test -scheme OpenWorktimeTrackerTestsruns 282 tests. The new notification test classes all pass.mainat b6aa5e5):ViewLayoutTests.testSettingsRowsRemainReadableInBothLanguagesAndAppearancesfails with 7 OCR assertions.Open question
If normal or critical is configured above the milestone (the settings allow it), the milestone does not suppress them; they still fire when reached.
Checklist
make test): everything except the OCR test above, which also fails onmainmake lint): 0 serious, same 5 length warnings asmain@Observable(notObservableObject)DesignTokensfor colors/typography (no UI changes)🤖 Generated with Claude Code
https://claude.ai/code/session_01WFc8P7zoT4V7GQaqwegkcm