refactor: relocate Apple supports()/unsupportedHint() closures onto the plugin — Phase 3 b.2 (#973)#993
Conversation
Size Report
Startup median (7 runs, lower is better):
Top changed chunks:
|
|
Reviewed current head The PR moves the Apple The parity coverage is the important part here: it keeps independent verbatim references, checks the Apple plugin key set, checks relocated closure behavior across sample devices, checks hint strings, and confirms non-Apple plugins did not grow accidental gates. Checks are green and the size report is negligible. |
…he plugin (#973) Phase 3 step b.2. Move the per-command supports() / unsupportedHint() device closures VERBATIM off the command-descriptor facet onto the owning PlatformPlugin's capability.supportsByDefault / unsupportedHintByDefault (perfect-shape §7 / ADR-0009: relocate, never flatten). Bodies are byte-for-byte identical; only their ownership moves to the Apple plugin, the family that owns every discriminating device (macOS-coordinate-pinch, tvOS-no-touch, physical-iOS, two-finger-synthesis). The relocation is faithful because every closure is a no-op (returns true / undefined) on non-Apple devices, so consulting it only for the Apple family leaves admission unchanged across the full device matrix. isCommandSupportedOnDevice and unsupportedHintForDevice now read the closure off getPlugin(device.platform); the command facet carries platform/kind buckets only, and supports/unsupportedHint are removed from the CommandCapability type. Parity gate (byte-for-byte, before deleting the hand sites): independent VERBATIM oracle in capability-plugin-routing-parity.test.ts pins (a) production admission + hint output unchanged across the {platform x command x kind x target} matrix, and (b) the relocated Apple-plugin closures are behaviorally identical to the originals across the device-fixtures sample matrix, with a guard that no non-Apple family grew a gate.
1ea4b86 to
0fd2f95
Compare
|
Rebased onto main (now includes #988/#990/#991/#992). Resolved 2 conflicts:
Re-verified after rebase (all green): tsc, oxlint --deny-warnings, oxfmt --check, layering guard, full unit suite (2897), fallow. The b.2 parity, d.2 tvOS, and b.3 appLog tests all coexist. Optional follow-up (not done, to keep the rebase faithful): the relocated closures still use |
|
Phase 3 step b.2 — relocate the Apple
supports()/unsupportedHint()closures onto the PlatformPluginCloses #973 (part of #972). Moves the per-command
supports()/unsupportedHint()device closures VERBATIM off the command-descriptor facet onto the owning plugin'scapability.supportsByDefault/unsupportedHintByDefault(perfect-shape §7 / ADR-0009: relocate, never flatten). Behaviorless, parity-gated, no leaf code touched.What moved (verbatim)
The closures at
src/core/command-descriptor/registry.ts:41-59(isNotMacOs,isMacOsOrAppleSimulator,isIosMobileSimulator,supportsSynthesisGesture,supportsAndroidOrIosNonTv,synthesisGestureUnsupportedHint) plus the inlineclipboard/alert/settingsclosures now live on the Apple plugin insrc/core/platform-plugin/register-builtins.ts, keyed by command inAPPLE_SUPPORTS_BY_DEFAULT/APPLE_UNSUPPORTED_HINT_BY_DEFAULT. Bodies are byte-for-byte identical — only ownership moved. ThesynthesisGestureUnsupportedHintmacOS-coordinate-pinch / tvOS-no-touch / physical-iOS strings are preserved exactly.Why the Apple plugin (the faithfulness argument)
supportsByDefaultis per-family; the closures are per-command — the tension PR #965 flagged when it deferred this step. The resolution: every one of these closures is a no-op on non-Apple devices — it returnstruefor android/linux that pass the bucket+kind check (or the command's non-Apple bucket already rejects the device beforesupportsruns), and the hint closures returnundefinedoff Apple. So the discriminating logic is entirely Apple-family. Consulting the closure only for the family that ownsdevice.platform(i.e. Apple) is therefore byte-for-byte identical to the old command-facet gate. This is verified exhaustively (0 mismatches over the full platform×kind×target cross-product) before any hand site was deleted.To keep the per-command shape without flattening to data, the plugin carries the closures as a command-keyed map of closures (
Readonly<Record<string, (device) => boolean>>), not a boolean table — the device-shaped logic stays as closures.Wiring
src/core/capabilities.ts:isCommandSupportedOnDevicereadsplugin.capability.supportsByDefault?.[command];unsupportedHintForDevicereadstryGetPlugin(device.platform)?.capability.unsupportedHintByDefault?.[command].supports/unsupportedHintare removed from theCommandCapabilitytype.src/core/command-descriptor/registry.ts: closure defs deleted,supports:/unsupportedHint:stripped from every entry, unusedDeviceInfoimport dropped. The facet now carries platform/kind buckets only.src/core/platform-plugin/plugin.ts:capability.supportsByDefaultre-typed from the reserved per-family method to the per-command map, plus a newunsupportedHintByDefaultcounterpart.Parity gate (before deleting the hand sites)
src/core/__tests__/capability-plugin-routing-parity.test.ts(independent VERBATIM oracle, unchanged copies of the closures):isCommandSupportedOnDeviceover the full{command × device}matrix still equals the before-pipeline reference (descriptor-fold bucket + verbatim supports + kind). Proves admission is unchanged.unsupportedHintForDeviceis string-equal to the verbatim hint reference across the full matrix.the Apple plugin carries exactly the relocated supports/hint closures— the plugin maps' key sets equal the verbatim reference (nothing dropped/added); ios and macos share one map.the relocated Apple closures are byte-for-byte the verbatim originals— every relocated closure returns identical boolean / identical hint string vs the verbatim copy for every command ×device-fixtures.tssample-device.no non-Apple family carries a relocated supports/hint closure— guards the faithfulness precondition (android/linux/web have no per-command gate).command-descriptor/__tests__/parity.test.tsupdated (capability entries are now selectable by platform bucket alone).Local verification (worktree, binaries direct)
tsc -p tsconfig.json✓oxlint . --deny-warnings✓ (exit 0)oxfmt --write && --check src test✓node scripts/layering/check.ts✓ (635 files, R1/R2/R3)rslib build✓vitest run --project unit✓ — 296 files / 2885 tests, no android flake this runfallow audit --base origin/main✓ — no issues in 7 changed filesDeferred / notes
supports()/unsupportedHint()closure was relocated and parity-proven.capability-plugin-routing-parity.test.tsheader comment claiming the closures "cannot move to the plugin's per-familysupportsByDefaultwithout flattening" is rewritten accordingly — the no-op-off-Apple property is what makes the move faithful.