# RC116 · Pass list active progress QA

## Scope

RC116 builds directly on RC115. The release is intentionally narrow and stays inside the existing pass player lifecycle:

- Style and standardize the active pass list.
- Make the active exercise/rest item render as the first/top row in the pass list.
- Add progress-fill timing for active pass-list rows.
- Use exact rest duration for rest rows.
- Use centralized master exercise timing hints for exercise rows, based on `exerciseKey`/master exercise identity and current set prescription.
- Keep player/video/timer/wake-lock lifecycle unchanged.

No new player lifecycle, video-source model, image model, cutout/layered model, or parallel renderer was introduced.

## Reused code paths / classes

RC116 keeps using:

- `preview.html` active pass structure.
- `.next-pass-screen`
- `.next-pass-layout`
- `.next-pass-media-card`
- `#videoWrap.next-pass-video-wrap`
- `#passVideoControls.next-pass-video-controls`
- `.next-pass-info-card`
- `.next-pass-progress-below`
- `.next-pass-playlist-card`
- `#miniList.next-pass-mini-list`
- `assets/js/renderers/pass-player-renderer.js`
- `assets/js/core/exercise-catalog.js`
- `assets/js/app.js` player lifecycle: `startWorkout`, `renderStep`, `renderVideo`, `renderRest`, timers, preload, wake lock.

## Changes

### Centralized exercise timing hints

`assets/js/core/exercise-catalog.js` now owns rough per-exercise timing hints through:

- `MASTER_TIMING`
- `timingForKey()`
- `estimateSecondsForPrescription()`

Examples verified:

- `Burpee + 3 reps` → `6s`
- `Push Up + 4 reps` → `8s`
- `Pogohopp framåt + 9 m` → estimated from distance timing.

Pass rows still own prescription data. The exercise catalog only supplies rough timing assumptions per master exercise identity.

### Mini-list renderer contract

`assets/js/renderers/pass-player-renderer.js` now owns mini-list item markup through:

- `miniListItem()`

The helper emits the existing legacy-compatible classes plus new stable classes:

- `.next-pass-mini-item`
- `.next-pass-mini-fill`
- `.next-pass-mini-index`
- `.next-pass-mini-copy`
- `.next-pass-mini-title`
- `.next-pass-mini-subtitle`

This keeps the sensitive player lifecycle in `app.js`, while moving repeated pass-list markup toward the renderer/component standard.

### Active item first/top

`app.js` now rotates the pass-list item array before render so the active exercise/rest item is first in DOM order. On desktop, CSS makes the active item span the full top row.

### Fill timing

- Rest rows use actual rest seconds: `rest * 1000`.
- Exercise rows use `NEXTExerciseCatalog.estimateSecondsForPrescription(step)` where possible.
- If no prescription estimate is possible, the existing `estimateWorkSeconds(step)` remains the fallback.
- Fill duration is bounded to keep the UI useful: minimum `3s`, maximum `90s`.

## CSS ownership

RC116 puts the pass-list visual system in `assets/css/next-system.css` using the existing NEXT tokens:

- `--next-card-border`
- `--next-card-border-strong`
- `--next-accent`
- `--next-text`
- `--next-muted`

The old `.mini-item` compatibility hooks remain, but RC116 styling is centered on `.next-pass-mini-*` classes.

## Real-DOM QA

Real-DOM QA was run with actual `preview.html`, actual CSS and actual JS via Playwright `page.set_content()`. External network/iframe requests were blocked/mocked as in RC108–RC115 QA.

Generated RC116 screenshots:

- `qa_screenshots/rc116_pass_list_video_mobile_390x844.png`
- `qa_screenshots/rc116_pass_list_video_ipad_820x1180.png`
- `qa_screenshots/rc116_pass_list_video_desktop_1440x1024.png`
- `qa_screenshots/rc116_pass_list_rest_desktop_1440x1024.png`

Measured checks in `qa_screenshots/rc116_pass_list_dom_metrics.json`:

- Playlist is visible when enabled.
- Active item is first in DOM order.
- Active item is aligned to top of list.
- Desktop active item spans the full first row.
- Exercise active fill uses estimated timing, not the old fixed 10s fallback.
- Rest active fill uses exact rest duration.
- Burpee timing helper returns `6s` for `3 reps`.
- Mini-list rows use `.next-pass-mini-item` renderer classes.
- No broken local images.

## Commands run

```bash
node tests/rc116_pass_list_progress_smoke.js
node tests/rc115_pass_player_scale_smoke.js
node tests/rc114_pass_media_contract_smoke.js
node tests/rc113_pass_video_controls_smoke.js
node tests/rc112_pass_chrome_reposition_smoke.js
node tests/rc111_pass_player_standardization_smoke.js
node tests/rc110_pass_page_standardization_smoke.js
node tests/rc109_asset_path_cleanup_smoke.js
node tests/rc107_asset_and_library_smoke.js
node tests/rc109_library_compactness_static_smoke.js
node tests/rc104_direct_composite_smoke.js
node tests/rc106_smoke.js assets/js/core/exercise-illustrations.js "$PWD"
find assets/js -name '*.js' -print0 | xargs -0 -n1 node --check
php -l ota_youtube_proxy.php
php -l video_backup_api.php
python3 tests/rc116_pass_list_real_dom_qa.py
python3 tests/rc115_pass_player_scale_real_dom_qa.py
python3 tests/rc114_pass_media_contract_real_dom_qa.py --child image desktop 1440 1024
python3 tests/rc114_pass_media_contract_real_dom_qa.py --child image mobile 390 844
unzip -t next_v96_rc116_pass_list_active_progress.zip
```

## Caveat

The actual deployed host was not tested from this sandbox. Screenshots/metrics are real preview DOM/CSS/JS via the established `page.set_content()` QA path. External YouTube iframes are blocked in sandbox screenshots, so video boxes may show the browser’s iframe placeholder even though the DOM/source path is verified.
