MOTION: token guard misses transition helpers and script-created transitions #729

Open
opened 2026-10-02 13:06:33 +00:00 by kayg · 5 comments
Owner

Context

Static rev-consistency review for #427 on origin/dev at c4a61e8cf090170f35b1bed3350d9de20c83ecd5. Follow-up to closed #477. DESIGN §34 and packages/ui/src/motion.ts require shared duration and easing roles. Keyboard and pointer actions keep the same timing (#611); reduced motion still applies.

Evidence

  • packages/ui/src/components/composer/DraftStack.svelte:60-62 returns fly(node, { y: 12, duration: 200 }) from a transition helper.
  • packages/ui/src/components/calendar/AttachmentDeck.svelte:107 declares FAN_MS = 180; it is passed to flipGroup at lines 280-283. The same file also declares local opening and closing times (see lines 108-109).
  • apps/web/src/lib/flip.ts:374-380 defines a default 240 ms and a literal cubic-bezier curve, then builds an inline CSS transition. The attachment deck passes duration options but uses the helper's local default easing.
  • apps/web/scripts/check-motion-tokens.mjs:23 only recognises inline Svelte double-brace option objects. It does not inspect transition helper calls or script-created transition strings.
  • Running node apps/web/scripts/check-motion-tokens.mjs prints UI transitions and animation options use shared motion tokens or documented exceptions. and exits 0 on this source.
  • Calling findMotionTokenViolations on function cardTransition(node) { return fly(node, { y: 12, duration: 200 }); } returns []. The CSS control transition: transform 200ms ease; is detected.

Expected and shared fix

Move the helper duration/easing defaults and repeated deck timings to shared motion roles. Extend the guard to cover authored transition helpers and inline script transitions. A documented one-off exception must still be allowed. Do not flag data timeouts, upload retries or preview retention times as animation timings.

Test idea

Add guard fixtures for fly/fade helper calls, aliases, option constants and script-created transition strings. Verify that literal timings fail, shared imports pass and reduced-motion zero passes. Keep the existing CSS fixtures. Check the deck and draft transitions after a shared token change so a local value cannot silently stay behind.

Searched open and closed issues for motion guard and read #477 and #611. #477 is closed and its current guard passes this source; this is its script-coverage follow-up. #611 covers input timing parity, not guard coverage.

## Context Static rev-consistency review for #427 on `origin/dev` at `c4a61e8cf090170f35b1bed3350d9de20c83ecd5`. Follow-up to closed #477. DESIGN §34 and `packages/ui/src/motion.ts` require shared duration and easing roles. Keyboard and pointer actions keep the same timing (#611); reduced motion still applies. ## Evidence - `packages/ui/src/components/composer/DraftStack.svelte:60-62` returns `fly(node, { y: 12, duration: 200 })` from a transition helper. - `packages/ui/src/components/calendar/AttachmentDeck.svelte:107` declares `FAN_MS = 180`; it is passed to `flipGroup` at lines 280-283. The same file also declares local opening and closing times (see lines 108-109). - `apps/web/src/lib/flip.ts:374-380` defines a default 240 ms and a literal cubic-bezier curve, then builds an inline CSS transition. The attachment deck passes duration options but uses the helper's local default easing. - `apps/web/scripts/check-motion-tokens.mjs:23` only recognises inline Svelte double-brace option objects. It does not inspect transition helper calls or script-created transition strings. - Running `node apps/web/scripts/check-motion-tokens.mjs` prints `UI transitions and animation options use shared motion tokens or documented exceptions.` and exits 0 on this source. - Calling `findMotionTokenViolations` on `function cardTransition(node) { return fly(node, { y: 12, duration: 200 }); }` returns `[]`. The CSS control `transition: transform 200ms ease;` is detected. ## Expected and shared fix Move the helper duration/easing defaults and repeated deck timings to shared motion roles. Extend the guard to cover authored transition helpers and inline script transitions. A documented one-off exception must still be allowed. Do not flag data timeouts, upload retries or preview retention times as animation timings. ## Test idea Add guard fixtures for `fly`/`fade` helper calls, aliases, option constants and script-created transition strings. Verify that literal timings fail, shared imports pass and reduced-motion zero passes. Keep the existing CSS fixtures. Check the deck and draft transitions after a shared token change so a local value cannot silently stay behind. ## Duplicate search Searched open and closed issues for `motion guard` and read #477 and #611. #477 is closed and its current guard passes this source; this is its script-coverage follow-up. #611 covers input timing parity, not guard coverage.
Author
Owner

Evidence line correction: AttachmentDeck.svelte declares OPEN_MS = 220 and CLOSE_MS = 160 at lines 303-304, not lines 108-109. FAN_MS = 180 is at line 107. The source snapshot is still c4a61e8cf090170f35b1bed3350d9de20c83ecd5.

Evidence line correction: `AttachmentDeck.svelte` declares `OPEN_MS = 220` and `CLOSE_MS = 160` at lines 303-304, not lines 108-109. `FAN_MS = 180` is at line 107. The source snapshot is still `c4a61e8cf090170f35b1bed3350d9de20c83ecd5`.
Author
Owner

Starting the reuse pass for #727, #729, #730 and #799 on branch job/reuse.

Starting commit/base: 2f4482ded066d9c5d9c59130377907f7fd2916c9, the same commit as job/merge-round-7a. I will merge origin/dev and re-merge job/merge-round-7a once before final gates.

Starting the reuse pass for #727, #729, #730 and #799 on branch `job/reuse`. Starting commit/base: `2f4482ded066d9c5d9c59130377907f7fd2916c9`, the same commit as `job/merge-round-7a`. I will merge `origin/dev` and re-merge `job/merge-round-7a` once before final gates.
Author
Owner

Implementation evidence for #729: the guard now scans calls to Svelte transition helpers and flipGroup, including imported aliases and options constants. It also follows constants used by script-written style.transition strings. The tests cover literal helper options, shared motion imports, zero-duration reduced motion and ignored retry timers. The helper-call regression failed on the old guard because it returned no violations; the generated-transition regression also failed on the old guard because it missed the easing.

Updated DraftStack and AttachmentDeck to use the existing DUR/durationMs roles. flipGroup keeps its prior 240 ms and ease-out defaults through DUR.morph and EASE_CSS.out, imported from the existing @calternal/ui/motion subpath.

Guard output, verbatim:

UI transitions and animation options use shared motion tokens or documented exceptions.

Focused test output, verbatim:

 Test Files  1 passed (1)
      Tests  8 passed (8)

Commit: b1cf763ab.

Implementation evidence for #729: the guard now scans calls to Svelte transition helpers and `flipGroup`, including imported aliases and options constants. It also follows constants used by script-written `style.transition` strings. The tests cover literal helper options, shared motion imports, zero-duration reduced motion and ignored retry timers. The helper-call regression failed on the old guard because it returned no violations; the generated-transition regression also failed on the old guard because it missed the easing. Updated DraftStack and AttachmentDeck to use the existing `DUR`/`durationMs` roles. `flipGroup` keeps its prior 240 ms and ease-out defaults through `DUR.morph` and `EASE_CSS.out`, imported from the existing `@calternal/ui/motion` subpath. Guard output, verbatim: ```text UI transitions and animation options use shared motion tokens or documented exceptions. ``` Focused test output, verbatim: ```text Test Files 1 passed (1) Tests 8 passed (8) ``` Commit: `b1cf763ab`.
Author
Owner

The merged-head bun run check found three strict JavaScript typing errors in the #729 motion scanner: source[start] could be undefined for the delimiter map key, and the helper's violations array lacked an element type. Fixed in b02e9ffa5 by using charAt() (empty for an out-of-range index) and declaring the array as string[].

Focused regression suite after the fix: bun run test --maxWorkers=1 src/lib/styles/motion-token-check.test.js → Test Files 1 passed (1), Tests 8 passed (8).

The merged-head `bun run check` found three strict JavaScript typing errors in the #729 motion scanner: `source[start]` could be undefined for the delimiter map key, and the helper's `violations` array lacked an element type. Fixed in `b02e9ffa5` by using `charAt()` (empty for an out-of-range index) and declaring the array as `string[]`. Focused regression suite after the fix: `bun run test --maxWorkers=1 src/lib/styles/motion-token-check.test.js` → `Test Files 1 passed (1)`, `Tests 8 passed (8)`.
Author
Owner

Finished on branch job/reuse at head b5544daeda. Motion-token scanning now covers script helpers, aliases, constants, flipGroup, and inline transition values; affected UI code uses shared motion roles. Focused regression tests passed (8/8), and bun run check passed with 0 errors and 0 warnings. The full serialized web suite ran 3,563.01s and failed only on 7 timeouts under host load (1,075/1,082 tests passed); details and exact output are in the final #727 report. Required production screenshot matrix could not run because the media sandbox guard detected 6,188 local threads (limit 4,096). No Rust source changed, so Rust crate gates were not applicable. No merge or push performed.

Finished on branch job/reuse at head b5544daedac6d8027a323167d9b188a5262d6eb5. Motion-token scanning now covers script helpers, aliases, constants, flipGroup, and inline transition values; affected UI code uses shared motion roles. Focused regression tests passed (8/8), and bun run check passed with 0 errors and 0 warnings. The full serialized web suite ran 3,563.01s and failed only on 7 timeouts under host load (1,075/1,082 tests passed); details and exact output are in the final #727 report. Required production screenshot matrix could not run because the media sandbox guard detected 6,188 local threads (limit 4,096). No Rust source changed, so Rust crate gates were not applicable. No merge or push performed.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal#729
No description provided.