- motionContextToDocs: escape regex metacharacters in arrayAfterKey /
scalarAfterKey key interpolation (safe today for \\w+ keys; now safe for
any future caller), and document balancedBlock's no-strings invariant.
- verify-motion.mjs: execSync shell string -> spawnSync with array args
(JSON.stringify is not shell escaping); verifier re-calibrated unchanged
(faithful render still PASS at min 20.30dB).
- command-failure-tracking: rebase folded the group-delegation skip into
upstream's recursive wrapCommand (HF#2033) — leaf commands now assert
their own flag tables, so `figma component --namee` is rejected at the
leaf while `--name` passes the group; heuristic invariant documented.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two guarantees so figma-motion imports can't drift from the design again:
- motionContextToDocs(): raw get_motion_context response -> MotionDoc[],
in code. Parses the motion.dev snippets (the reliable encoding; the CSS
snippets stretch durations and can disagree), strips loop-wrap tail
keyframes (sub-ms segments at the window end are the loop reset, not
authored motion), preserves bezier eases verbatim. Fixture test uses the
verbatim response from a real Motion timeline whose translation was
frame-validated against Figma's own export_video render.
- skills/figma/scripts/verify-motion.mjs: mandatory post-render gate.
Compares motion-energy deltas between the render and the export_video
ground truth so static import fidelity cancels out and the score
isolates choreography. Calibrated on a faithful translation (min 20.3dB)
vs a diverging one (min 5.0dB); threshold 15dB.
The skill's Motion step now routes through both: no hand transcription,
no unverified completion.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>