Fun Layer pack + catalog collision tests#319
Conversation
Adds the Function / Media pack (Leader → f → fun layer: right hand becomes an F-key numpad grid, left hand is media/brightness). Closes the "blocked" status of Fun Layer in the migration plan — just a momentaryActivator away all along. Before shipping the pack, adds three static guards to catch collision-shaped bugs: * `RuleCollectionCollisionTests.testNoTwoCollectionsShareAnActivator` — asserts only one collection owns each `(sourceLayer, key)` activator pair, with an allow-list for the intentionally-mutually-exclusive nav providers (Vim Navigation, KindaVim, Neovim Terminal all use Space→nav). * `RuleCollectionCollisionTests.testNoTwoCollectionsMapTheSameInputInTheSameLayer` — asserts no two collections bind the same input key to different outputs within the same target layer. * `RuleCollectionKanataValidationTests.testEveryCatalogCollectionEnabledAtOnce` — runs `kanata --check` against a config with every collection enabled, catching emergent combined-state issues. The new tests surfaced real existing bugs in the current Mission Control pack: * Mission Control had its own Space→nav activator which collided with Vim Navigation's. Removed — MC is now an additive nav-layer pack that piggybacks on whichever nav provider the user has enabled. * Mission Control mapped `e`, `[`, `]` in nav layer, which KindaVim already claims (`e`=end-of-word, `[`/`]`=paragraph up/down). Moved to unclaimed keys: `q` (Exposé), `t` (Show Desktop), `,` / `.` (prev / next Desktop). `m` and `c` were already safe. Updated Mission Control pack copy and runtime behavior test to reflect the new key layout and the nav-provider dependency. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Code Review — PR #319: Fun Layer pack + catalog collision testsOverviewClean, well-motivated PR. The Fun Layer follows the exact same two-step pattern as Numpad/Symbol (Space → nav → Issues1. Fragile name-based lookup in activator collision test (Medium)
var claimed: [String: String] = [:] // key → collection.name
// …
if let existingCollection = collections.first(where: { $0.name == existing }),
navProviderIDs.contains(existingCollection.id)If any nav-provider collection is renamed the allow-list silently stops working — the lookup returns var claimed: [String: (name: String, id: UUID)] = [:]
// …
claimed[key] = (collection.name, collection.id)
// …
if navProviderIDs.contains(collection.id),
let existing = claimed[key],
navProviderIDs.contains(existing.id)
{
continue
}2. Silent breakage for existing Mission Control users (Medium)Removing Worth considering: a validation pass in 3. Multi-line comment blocks in production/test files (Low)CLAUDE.md is explicit: "Never write multi-paragraph docstrings or multi-line comment blocks — one short line max." A few spots in this PR add multi-line blocks:
These should be trimmed to a single explanatory line each. 4.
|
Summary
Fun Layer pack — unblocked by giving the collection its own nested-layer activator (
Leader → f → fun), same pattern as Numpad and Symbol. Right hand becomes an F-key grid (u/i/o = F7/F8/F9, j/k/l = F4/F5/F6, m/,/. = F1/F2/F3 + n/,// = F10/F11/F12), left hand is media/brightness.Catalog collision tests (added before shipping Fun so the new activator is validated):
testNoTwoCollectionsShareAnActivator— guards against duplicate(sourceLayer, key)activator pairs. Allow-list for the three nav providers (Vim Nav / KindaVim / Neovim Terminal) which intentionally shareSpace→nav.testNoTwoCollectionsMapTheSameInputInTheSameLayer— guards against silently-overridden mappings in the same target layer.testEveryCatalogCollectionEnabledAtOnce— runskanata --checkon a config with every collection on.Real bugs surfaced
The collision tests immediately caught two existing Mission Control issues from my earlier redesign:
Space→navactivator that collided with Vim Nav's. Removed — MC is now purely additive, piggybacks on whichever nav provider is enabled. Pack description updated to note the dependency.e,[,]in nav layer, conflicting with KindaVim'se=end-of-word/[=paragraph up /]=paragraph down. Moved to unclaimed keys:q(Exposé),t(Show Desktop),,/.(prev / next Desktop).m(Mission) andc(Notifications) were already safe.Test plan
swift testpasses (420 tests)🤖 Generated with Claude Code