|
| 1 | +# Tier 4 — escape-hatch |
| 2 | + |
| 3 | +## What it tests |
| 4 | + |
| 5 | +T4 is the **lint-only** tier. There are no renders to diff — the skill is |
| 6 | +graded on whether it correctly _refuses_ to translate each case (and |
| 7 | +recommends the runtime interop pattern from PR #214 instead) or, where |
| 8 | +appropriate, translates after dropping warning-level decorations. |
| 9 | + |
| 10 | +Each `cases/*.tsx` file is a minimal Remotion composition that |
| 11 | +demonstrates one specific pattern. The skill should: |
| 12 | + |
| 13 | +1. Run `scripts/lint_source.py` over the source. |
| 14 | +2. Compare the JSON output to `expected.json` for that case. |
| 15 | +3. Take the documented `skill_action`: |
| 16 | + - `refuse_translation_recommend_interop` — print the rationale + link to |
| 17 | + the PR #214 interop guide; do not produce HF output. |
| 18 | + - `drop_lambda_code_translate_remainder_if_clean` — drop the |
| 19 | + `@remotion/lambda` code with a note; translate the rest only if no |
| 20 | + other blockers are present. |
| 21 | + - `translate_after_dropping_wrappers` — translate normally; drop |
| 22 | + `useCallback` / `useMemo` / `delayRender` wrappers. |
| 23 | + - `inline_hook_body_if_pure` — inline the custom hook's body if it's a |
| 24 | + pure derivation of `useCurrentFrame`; otherwise bow out. |
| 25 | + |
| 26 | +## Cases |
| 27 | + |
| 28 | +| # | File | Expected blocker | Notes | |
| 29 | +| --- | -------------------------- | ----------------------------- | ------------------------------------------- | |
| 30 | +| 01 | `01-use-state.tsx` | `r2hf/use-state` | useState driving animation | |
| 31 | +| 02 | `02-use-effect-deps.tsx` | `r2hf/use-effect-deps` | useEffect with non-empty deps + side effect | |
| 32 | +| 03 | `03-async-metadata.tsx` | `r2hf/async-metadata` | calculateMetadata returns a Promise | |
| 33 | +| 04 | `04-third-party-react.tsx` | `r2hf/third-party-react-ui` | imports `@mui/material` | |
| 34 | +| 05 | `05-lambda-config.tsx` | `r2hf/lambda-import` | imports `@remotion/lambda` | |
| 35 | +| 06 | `06-warnings-only.tsx` | (warnings only) | delayRender / useCallback / useMemo | |
| 36 | +| 07 | `07-custom-hook.tsx` | (warnings only) | locally-defined `useFadeIn` | |
| 37 | +| 08 | `08-mixed.tsx` | useState + useEffect + chakra | aggregate-findings test | |
| 38 | + |
| 39 | +## Validation |
| 40 | + |
| 41 | +```bash |
| 42 | +./validate.sh |
| 43 | +``` |
| 44 | + |
| 45 | +The script runs `lint_source.py` against each case and asserts: |
| 46 | + |
| 47 | +- Each expected blocker rule fires with severity `blocker`. |
| 48 | +- Each expected warning rule fires with severity `warning` (or stronger). |
| 49 | +- `lint_source.py`'s exit code is 1 when blockers are expected, 0 otherwise. |
| 50 | + |
| 51 | +T4 passes when every case matches its expected output. No renders involved. |
0 commit comments