Skip to content

Add 2-4 word length preset (closes #475)#480

Merged
FuJacob merged 1 commit into
mainfrom
feat/word-count-2-4-preset
May 31, 2026
Merged

Add 2-4 word length preset (closes #475)#480
FuJacob merged 1 commit into
mainfrom
feat/word-count-2-4-preset

Conversation

@FuJacob

@FuJacob FuJacob commented May 31, 2026

Copy link
Copy Markdown
Owner

Summary

Adds a new "2-4 words" option to the suggestion length picker (settings + menu bar), as requested in #475. The previous "3-7" tier is renamed to "4-7" so the lower bound of each tier matches the upper bound of the previous tier, keeping the chain consistent with the existing 7-12 and 12-20 tiers. The 4-7 tier keeps the same 11-token budget the old 3-7 had, so its behavior is unchanged.

Validation

xcodebuild -project Cotabby.xcodeproj -scheme Cotabby -destination 'platform=macOS' build
# ** BUILD SUCCEEDED **

xcodebuild test -project Cotabby.xcodeproj -scheme Cotabby \
  -destination 'platform=macOS' \
  -only-testing:CotabbyTests/SuggestionModelValueTests \
  -only-testing:CotabbyTests/OnboardingTemplateRecommenderTests \
  CODE_SIGNING_ALLOWED=NO
# ** TEST SUCCEEDED ** 19 tests, 0 failures

swiftlint lint --quiet Cotabby/Models/SuggestionModels.swift \
  Cotabby/Models/SuggestionSettingsModel.swift \
  Cotabby/Models/OnboardingTemplate.swift \
  CotabbyTests/ModelAndPresentationValueTests.swift \
  CotabbyTests/OnboardingTemplateRecommenderTests.swift
# exit 0

Linked issues

Closes #475.

Risk / rollout notes

  • Persisted-settings migration: SuggestionSettingsModel now rewrites the legacy "3-7" raw value to .fourToSeven on launch. Without this users on the short tier would silently fall back to the default 12-20 after the rename, which would be a worse experience than the issue is trying to add.
  • The "Quick" onboarding template now maps to .fourToSeven instead of .threeToSeven. Same token budget (11) and same upper word bound (7), so behavior is preserved for users completing onboarding after this lands. Deliberately did not retarget Quick to the new shorter .twoToFour to keep this PR scoped to the issue.
  • Token budget for the new .twoToFour tier is 6 (matches the existing ~1.5x upper-bound rule documented in the enum).

Greptile Summary

Adds a new 2-4 word-count preset (twoToFour) to the suggestion length picker and renames the old 3-7 tier to 4-7 (fourToSeven) so tier boundaries chain cleanly. A UserDefaults migration in SuggestionSettingsModel silently upgrades any persisted \"3-7\" raw value to .fourToSeven on launch, preventing existing users from falling back to the default preset.

  • New enum case twoToFour = \"2-4\" with a token budget of 6 (consistent with the ~1.5× upper-bound rule); fourToSeven inherits the old threeToSeven budget of 11.
  • Migration reads the legacy \"3-7\" key and rewrites it to \"4-7\" in-process at init, then persists the new value — a one-shot, invisible upgrade.
  • Onboarding "Quick" template re-targets to .fourToSeven (same token budget and upper word bound as before), keeping new-user behavior unchanged.

Confidence Score: 4/5

Safe to merge; the enum rename, migration, and onboarding re-targeting are all correct and consistent.

The migration in SuggestionSettingsModel is the most sensitive part of the change — existing users who had selected the old shortest tier depend on it to land on .fourToSeven rather than the app default. The logic itself is correct, but there is no dedicated unit test exercising this UserDefaults upgrade path. If the guard were accidentally removed in a future refactor, the test suite would not catch it. Everything else — the enum, token budgets, onboarding template, and updated tests — is well-structured and internally consistent.

The migration block in SuggestionSettingsModel.swift (lines 176-186) would benefit from a companion test seeding "3-7" into an isolated UserDefaults suite and asserting the loaded preset is .fourToSeven.

Important Files Changed

Filename Overview
Cotabby/Models/SuggestionModels.swift Adds twoToFour = "2-4" and renames threeToSeven to fourToSeven = "4-7"; token budgets follow the ~1.5x upper-bound rule consistently (6, 11, 18, 30).
Cotabby/Models/SuggestionSettingsModel.swift Adds a one-shot migration of the legacy "3-7" raw value to .fourToSeven at init time; the migration is correct but has no unit test covering the path.
Cotabby/Models/OnboardingTemplate.swift Re-targets the Quick onboarding template from threeToSeven to fourToSeven; behavior is preserved as the token budget and upper word bound are unchanged.
CotabbyTests/ModelAndPresentationValueTests.swift Adds assertions for both new/renamed presets (twoToFour and fourToSeven); exhaustively covers all four tiers' prompt instructions and token budgets.
CotabbyTests/OnboardingTemplateRecommenderTests.swift Updates the Quick preset assertion from .threeToSeven to .fourToSeven; remaining test assertions are unchanged and still pass.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[SuggestionSettingsModel init] --> B{Read UserDefaults selectedWordCountPreset}
    B -- nil --> E[Use configuration.defaultWordCountPreset]
    B -- storedRaw == 3-7 legacy --> C[Resolve to .fourToSeven]
    B -- valid current raw value --> D[Resolve via SuggestionWordCountPreset.init]
    B -- unknown invalid value --> E
    C --> F[persistSelectedWordCountPreset writes 4-7 back]
    D --> F
    E --> F
    F --> G[Published selectedWordCountPreset]
Loading

Fix All in Codex Fix All in Claude Code

Reviews (1): Last reviewed commit: "Add 2-4 word length preset and re-bound ..." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

Splits the previous 3-7 length tier into a new 2-4 option (for users
who want shorter, higher-precision completions) and a 4-7 option (the
former 3-7, lower bound bumped so it doesn't overlap with 2-4 and the
tier chain stays aligned with 7-12 and 12-20). Existing users whose
saved preset is '3-7' migrate to '4-7' on launch instead of silently
falling back to the default. Quick onboarding template also tracks
the rename. Closes #475.
Comment on lines +176 to +186
let resolvedWordCountPreset: SuggestionWordCountPreset = {
let storedRaw = userDefaults.string(forKey: Self.selectedWordCountPresetDefaultsKey)
// Migrate the retired "3-7" raw value to its replacement "4-7" so users who picked
// the short preset don't silently jump to the default after #475 split the short
// tier into 2-4 and 4-7.
if storedRaw == Self.legacyShortPresetRawValue {
return .fourToSeven
}
return storedRaw.flatMap(SuggestionWordCountPreset.init(rawValue:))
?? configuration.defaultWordCountPreset
}()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Missing test coverage for the "3-7" migration path

The migration of "3-7".fourToSeven is described in the PR description as the most important rollout concern (users silently jumping to the default preset), but there is no test that exercises this path in SuggestionSettingsModel. If someone accidentally removes or misplaces the if storedRaw == … guard in a future refactor, the test suite will still pass. The existing GhostTextOpacitySettingsTests already shows how to build an isolated UserDefaults suite and reload a SuggestionSettingsModel; the same pattern could seed "3-7" into selectedWordCountPresetDefaultsKey and assert the model reads back .fourToSeven.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Codex Fix in Claude Code

@FuJacob FuJacob merged commit 91de6b8 into main May 31, 2026
4 checks passed
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.

[Feature Request] 2-4 word suggestion setting

1 participant