|
| 1 | +# Model properties automatic updates |
| 2 | + |
| 3 | +## Behavior and source of truth |
| 4 | + |
| 5 | +The shared effort popover no longer has Cancel/Apply. Fast and Thinking switches |
| 6 | +apply immediately. Slider values preview locally while dragging or holding a |
| 7 | +range key, then apply once on pointer/key release or blur. Assistive input that |
| 8 | +does not generate pointer/key events applies immediately. The popup stays open; |
| 9 | +Escape and outside clicks dismiss it without reverting completed changes. |
| 10 | + |
| 11 | +The caller's model id is authoritative. Each completed control interaction |
| 12 | +resolves the full effort/thinking/fast combination before calling `onChange`. |
| 13 | +Unsupported Fast is cleared when moving to an effort without that variant; |
| 14 | +unavailable combinations and unchanged values do not reach the save callback. |
| 15 | +All four dropdown consumers keep their existing session/default-variant save |
| 16 | +paths. No provider calls, persistence formats, or backend behavior changed. |
| 17 | + |
| 18 | +The old popover draft/Apply effects and model-table preview map were removed. |
| 19 | +A slider keeps only one local interaction and preview, with no pending save timer |
| 20 | +or queue. Pointer cancel/unmount drops unfinished previews. Refreshed parent |
| 21 | +values invalidate stale gestures; switching model families remounts the slider. |
| 22 | +Normal effort updates preserve the input node and keyboard focus. |
| 23 | + |
| 24 | +The compact popup is left-aligned to its trigger so label width changes do not |
| 25 | +shift it sideways. It uses measured height for custom placement and omits the |
| 26 | +last section's bottom divider. The purple Ultra styling remains unchanged. |
| 27 | + |
| 28 | +## Architecture coverage |
| 29 | + |
| 30 | +Checked compilation, removal of dead preview state, callback naming, the shared |
| 31 | +selection/write boundary, invalid/default selections, all four entry points, |
| 32 | +and effort/Fast resolution. Provider wire formats, backend initialization, and |
| 33 | +cross-instance persistence were not changed or revalidated in this follow-up. |
| 34 | +Existing save-error and RPC ordering behavior remains owned by the callers; |
| 35 | +this change coalesces slider gestures before invoking those paths. |
| 36 | + |
| 37 | +## Lifecycle evidence |
| 38 | + |
| 39 | +| Area | Verdict | Evidence | Change or reason kept | Verification | |
| 40 | +| ------------------ | ------- | ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | |
| 41 | +| Background work | keep | No new timer, listener, worker, or deferred save | Existing dropdown listeners are open-scoped; existing slider motion pauses while hidden | Slider visibility/reopen tests and popup overlay dismissal tests | |
| 42 | +| Memory | fix | Removed popover draft bookkeeping and per-model preview map | One bounded gesture/preview lives in the mounted slider | Cancel/unmount regression test | |
| 43 | +| Scope/isolation | fix | Gesture captures the original parent value; family changes replace its owner | A refreshed value cannot be overwritten by a stale unfinished drag | Stale-drag and external-refresh tests | |
| 44 | +| Rendering/hot path | fix | Native input updates only local preview during a gesture | One save callback per drag or held-key interaction; switches call once | Pointer/key coalescing, duplicate-release, and keyboard-focus tests | |
| 45 | + |
| 46 | +## Verification |
| 47 | + |
| 48 | +- `pnpm exec vitest run --config config/vitest.config.ts src/components/ModelPropertiesDropdown/ModelPropertiesDropdown.test.ts src/components/ModelPropertiesDropdown/EffortSlider.test.ts src/util/__tests__/variantEditOptions.test.ts src/components/SelectorPill/index.test.ts src/components/Dropdown/positioning.portalTransform.test.ts src/components/Dropdown/positioning.verticalFit.test.ts`: 32 tests passed |
| 49 | +- `pnpm exec eslint src/components/ModelPropertiesDropdown/index.tsx src/components/ModelPropertiesDropdown/EffortSlider.tsx src/components/ModelPropertiesDropdown/ModelPropertiesDropdown.test.ts src/components/ModelPropertiesDropdown/EffortSlider.test.ts src/components/ModelSelectorPill/index.tsx src/scaffold/GlobalSpotlight/palettes/UnifiedModelPalette/VariantPill.tsx src/modules/MainApp/Integrations/KeyVault/shared/ModelTable/ModelVariantInlineCard.tsx src/modules/MainApp/Integrations/KeyVault/shared/ModelTable/modelTableGroupColumns.tsx --max-warnings 0`: passed |
| 50 | +- `pnpm run typecheck`: passed; the first run caught an unsupported test assertion, which was replaced with this repo's supported assertions |
| 51 | +- `node scripts/quality/check-test-placement.mjs`: passed across 440 directories |
| 52 | +- `git diff --check`: passed |
| 53 | + |
| 54 | +No desktop control, full-app visual inspection, actual account writes, or CPU/RSS |
| 55 | +measurements were used. Browser-native range event ordering in the packaged |
| 56 | +WebView was not manually verified. Tests use real React controls and the dropdown |
| 57 | +engine in jsdom, with controlled model updates at the public callback boundary. |
| 58 | +No measured runtime performance improvement is claimed. |
| 59 | + |
| 60 | +Performance verdict: **pass for this scoped change**. The bounded interaction, |
| 61 | +no-background-save, cleanup, and stale-input invariants pass the targeted tests. |
| 62 | +Desktop resource measurements and end-to-end persistence are not claimed. |
| 63 | + |
| 64 | +## WebKit drag regression (2026-09-01) |
| 65 | + |
| 66 | +Explicitly calling `setPointerCapture` on the range input prevents WebKit's |
| 67 | +native thumb from dragging. The component now leaves capture to the native |
| 68 | +thumb. Native release delivery still handles releases outside the rail; the |
| 69 | +existing one-save-per-gesture, keyboard, cancellation, and stale-value behavior |
| 70 | +is unchanged. No timers, listeners, caches, or persistence paths were added. |
| 71 | + |
| 72 | +A temporary headless Playwright fixture bundled the actual `EffortSlider.tsx` |
| 73 | +and compiled its SCSS, with a controlled parent and only translation stubbed. |
| 74 | +Real mouse movement reproduced the pre-fix WebKit failure: dragging Extra High |
| 75 | +to Ultra left the value at Extra High with no save. With the fix, WebKit 26.5 |
| 76 | +and Chromium passed drags in both directions, an outside-rail release, a track |
| 77 | +click, and an arrow-key change. Each completed gesture saved exactly once; |
| 78 | +active drags saved nothing and keyboard focus stayed on the range. |
| 79 | + |
| 80 | +The existing component regression now rejects capture on the input. Injected |
| 81 | +jsdom values only verify coalescing; they must not be used as proof that a |
| 82 | +native slider is draggable. The headless fixture is component-level evidence, |
| 83 | +not a packaged Tauri or full Spotlight end-to-end test. Actual account writes |
| 84 | +and the user's desktop remain untested. |
0 commit comments