# FreeCut PR #25 — frontend QA

## Status

**PASS**

This is a fresh real-browser run against exact HEAD `4f64f8e44dd741e1c48fc42023116db9c62747fe`.

## Environment

- Repository/worktree: `/Users/lightninglu10/Q5/.worktrees/freecut/v1-editor-hardening`
- Base URL: `http://localhost:5199`
- Browser: Playwright `1.60.0`, real Chromium, desktop `1280x720`; mobile smoke `390x844`
- Runtime: Node `v22.20.0` from `/Users/lightninglu10/.nvm/versions/node/v22.20.0/bin`; npm `11.8.0` via `npx --yes npm@11.8.0`
- Deterministic project: app-created `single-text` fixture, one `Hello World` item on V1, frames `0..180`, 30 fps, no media assets; the visible track also had an empty body region. WorkspaceGate and workspace-fs used a real Chromium OPFS directory handle; only the headless native folder picker was shimmed.
- Microphone: actual Record voiceover UI/controller path with Chromium fake media device and granted microphone permission; no product request interception or mock server.
- The in-app Browser MCP was unavailable and terminal-browser could not control the terminal pane, so direct Playwright Chromium was used. The browser run still exercised the real app and real DOM propagation.
- Source working tree remained clean at the tested head; no source, commit, push, PR-state, or merge operation was performed.

## Workflow evidence

| # | Workflow | Result | Evidence |
|---:|---|---|---|
| 1 | Deterministic project load with visible clip and empty track body | PASS | One rendered `Hello World` item (`0..180`), one V1 track, empty hit had `item=null`, no missing-media dialog. [`loaded-desktop.png`](./PR25-4f64f8e44dd741e1c48fc42023116db9c62747fe-loaded-desktop.png) |
| 2 | Active mic take, recording: clip click and empty-track/body click | PASS | Before clip: mic `recording`, transport playing at frame 35. After clip: still `recording`/playing, `pause=0`, `setPreviewFrame=0`, frame delta `0`. Empty body was a real DOM hit on the track; after it: still `recording`/playing, `pause=0`, `setPreviewFrame=0`, frame delta `6`, timeline remained one item/one track. [`mic-recording-clicks.png`](./PR25-4f64f8e44dd741e1c48fc42023116db9c62747fe-mic-recording-clicks.png) |
| 3 | Active mic take, paused: clip click and empty-track/body click | PASS | Actual Pause recording UI left mic `paused`, transport stopped at frame `126`; preview frame `42` was held. Both real DOM clicks preserved frame/preview/mic status and item/track counts exactly; all pause/seek/preview/scrub counters were `0`. [`mic-paused-clicks.png`](./PR25-4f64f8e44dd741e1c48fc42023116db9c62747fe-mic-paused-clicks.png) |
| 4 | Stop/reset take without commit | PASS | Actual Cancel recording UI returned mic to `idle`; timeline stayed one item/one track and no take was committed. |
| 5 | Normal clip click after reset | PASS | With current frame `30`, preview frame `60`, and mic `idle`, clip click produced current `60`, cleared preview, and left transport paused. Instrumentation recorded `pause=1`, `setPreviewFrame=1`, `setScrubFrame=1`; scrubber ended hidden with zero rect. [`normal-clip-committed.png`](./PR25-4f64f8e44dd741e1c48fc42023116db9c62747fe-normal-clip-committed.png) |
| 6 | Normal empty-track/body click and click-to-seek after reset | PASS | `elementFromPoint` confirmed the target had `item=null` and the V1 track id. Before: current `38`, playing; after: current `158`, paused, preview still null. Instrumentation recorded `pause=1`, `setCurrentFrame=1`; scrubber ended hidden with zero rect. [`normal-empty-track-seek.png`](./PR25-4f64f8e44dd741e1c48fc42023116db9c62747fe-normal-empty-track-seek.png) |
| 7 | Razor/Split discoverability and action | PASS | Real toolbar button was discoverable and set `activeTool=razor`; real clip click split one item into adjacent ranges `[0,135]` and `[135,180]` (item count `1→2`). [`razor-split.png`](./PR25-4f64f8e44dd741e1c48fc42023116db9c62747fe-razor-split.png) |
| 8 | Contiguous ripple delete | PASS | Real context menu exposed enabled `Ripple Delete`; deleting the first split half left the second half shifted from `135` to `0`, preserving its `45`-frame duration. [`contiguous-ripple-delete.png`](./PR25-4f64f8e44dd741e1c48fc42023116db9c62747fe-contiguous-ripple-delete.png) |

## Regression checks

- `Invalid source position` console hits: **0**.
- Stale skim/skim overlay console hits: **0**.
- Final preview scrubber: `display:none`, zero-sized bounding rect.
- The active-take checks used the actual toolbar/fake-media recording route and counted playback-store calls around each DOM click. Natural playback clock updates (`setCurrentFrame`) were allowed while recording; event-induced pause/preview/seek/finalize calls were absent.
- Mobile smoke at `390x844`: body width remained `390px` and the deterministic timeline item remained rendered. [`loaded-mobile.png`](./PR25-4f64f8e44dd741e1c48fc42023116db9c62747fe-loaded-mobile.png)

## Automated verification

- Focused timeline/component/item-handler suite: **8 files passed, 119 tests passed**, exit `0`. [`focused-tests.txt`](./PR25-4f64f8e44dd741e1c48fc42023116db9c62747fe-focused-tests.txt)
- `npm run check`: **exit `0`**, no warnings/lint/type errors in `2404` files. [`check.txt`](./PR25-4f64f8e44dd741e1c48fc42023116db9c62747fe-check.txt)
- `npm run build`: **exit `0`**, `4137` modules transformed and production build completed. Non-fatal bundler diagnostics are summarized in [`build.txt`](./PR25-4f64f8e44dd741e1c48fc42023116db9c62747fe-build.txt).

## Console and network

- Console errors: **0**.
- Page errors: **0**.
- Failed requests: **0**; [`network-failures.jsonl`](./PR25-4f64f8e44dd741e1c48fc42023116db9c62747fe-network-failures.jsonl) is empty.
- Console warnings: `77` total: `14` expected migration notices from the app-created fixture workspace upgrade (v2–v15), plus `63` Chromium/WebGPU `[Invalid Texture]` validation warnings emitted while rendering under headless SwiftShader. The latter are environment renderer warnings (not `Invalid source position`), did not produce page errors or failed requests, and did not prevent any requested workflow. Full raw capture: [`console.jsonl`](./PR25-4f64f8e44dd741e1c48fc42023116db9c62747fe-console.jsonl).

## Artifacts

- Machine-readable observations: [`observations.json`](./PR25-4f64f8e44dd741e1c48fc42023116db9c62747fe-observations.json)
- Interactive video: [`interactive-workflow.webm`](./PR25-4f64f8e44dd741e1c48fc42023116db9c62747fe-interactive-workflow.webm)
- Playwright trace: [`interactive-trace.zip`](./PR25-4f64f8e44dd741e1c48fc42023116db9c62747fe-interactive-trace.zip)
- JSON/JSONL manifest: [`artifact-manifest.json`](./PR25-4f64f8e44dd741e1c48fc42023116db9c62747fe-artifact-manifest.json)

All captures were visually inspected; they contain only the synthetic project name/`Hello World` fixture and no credentials or personal data. No public upload was attempted: this read-only local QA request supplied no approved artifact uploader, so manifest `url` fields are `null` and the durable local files above are the source of truth.

## Cleanup

The dedicated dev-server tab (`2d0dea32-2960-4b6d-b9d0-351831eb3f25`) and Playwright helper tab (`bdff8abc-cc2f-406b-a4c5-10c2368e60d9`) were deleted from workflow `3ad0d228-e337-43dc-822b-4fb78ad4c8ed`; port `5199` is free. No other workflow/server was touched.
