# TASKS Use this board to coordinate handoff between planner, implementer, and reviewer. Status values: - `in_planning` - `ready_for_implement` - `in_implementation` - `ready_for_review` - `in_review` - `ready_to_commit` - `changes_requested` - `done` Command expectations: - planner moves tasks into `in_planning` and `ready_for_implement` - implementer moves tasks into `in_implementation`, `ready_for_review`, and `done`, and resumes work from `changes_requested` and `ready_to_commit` - reviewer moves tasks into `in_review`, `ready_to_commit`, or `changes_requested` - `status_cycle` should report deterministic task status, current owner role, and next recommended action based on this board | Task ID | Scope | Status | Acceptance Criteria | Evidence | Next Role | | --- | --- | --- | --- | --- | --- | | T-001 | FastAPI backend (`app.py`) + inline HTML/JS frontend (`requirements.txt`) | done | `GET /` returns 200 with HTML containing "Download MP3"; `POST /download` with valid URL + mode streams a file; invalid URL returns 400 JSON with `.message` | Reviewer re-ran mocked FastAPI route checks (GET /, valid download, invalid/empty/missing-field errors, yt-dlp failure, unicode filename) — all passed; see `.ai/REVIEW.md` | none | | T-002 | Dockerfile + README.md (build/run docs) | done | `docker build -t yt-dl .` exits 0; `docker run --rm -p 8080:8080 yt-dl` starts server; `curl http://localhost:8080/` returns HTML with download buttons | Reviewer re-ran `docker build` + container smoke test, plus a live end-to-end MP3 and video download against a real YouTube URL through the container — all passed; see `.ai/REVIEW.md` | none | | T-003 | `app.py` (`noplaylist` option, `sanitize_filename` helper, title-based `FileResponse` filename, frontend `Content-Disposition`-based `link.download` fix) + `README.md` update | done | Pasting a playlist/`list=` URL downloads only the referenced video; saved filename matches the video title with emoji/icons stripped (normal chars kept) instead of a UUID, with correct extension; `python -m py_compile app.py` passes | Reviewer re-ran `py_compile`, unit-checked `sanitize_filename`, and ran a live end-to-end playlist-link MP3 download + a plain video download through the built Docker image against real YouTube URLs — all passed; see `.ai/REVIEW.md` | none | | T-004 | `app.py` (job-based `POST /download` + `GET /progress/{job_id}` + `GET /download/{job_id}/file`, in-memory job store, yt-dlp `progress_hooks`, frontend polling + progress bar UI) + `README.md` update | done | Progress bar appears below the buttons on download start and updates with percent/speed/downloaded-total size; file auto-delivers to the browser on completion with the correct sanitized filename; server-side failure shows an error in place of the bar with no crash; `python -m py_compile app.py` passes | Reviewer re-ran `py_compile` and drove the full job lifecycle live through the built Docker image against real YouTube URLs (progress polling, auto-delivered file, 404/409 semantics, server-side error path with no crash) — all passed; see `.ai/REVIEW.md` | none | | T-005 | `Dockerfile` (install Deno JS runtime) + `app.py` (point yt-dlp `ydl_opts` at the installed Deno binary and permit official EJS solver retrieval) + `README.md` update | done | `docker build` exits 0; `docker exec deno --version` succeeds; a video URL previously failing with `This video is not available` now downloads successfully; server logs no longer show `No supported JavaScript runtime could be found` during a download; playlist-single-video/progress-bar/filename behavior from T-003/T-004 is unaffected; `python -m py_compile app.py` passes | Reviewer re-ran `py_compile`, `docker build`, verified the `js_runtimes`/`remote_components` `ydl_opts` shape against the installed yt-dlp source, and drove live MP3 downloads (previously-failing URL + playlist-link regression) through the built Docker image — no missing-runtime warning, EJS solver fetched and used, single-video/progress/filename behavior intact; see `.ai/REVIEW.md` | none | | T-006 | `app.py` (`extractor_args.youtube.player_client` ordering in shared `ydl_opts`) + `README.md` update | done | A video URL previously failing with `Missing required Visitor Data` / `This video is not available` now downloads successfully via an alternate player client; existing playlist-single-video/progress-bar/filename/Deno behavior unaffected; failures still surface a clean UI error with no crash; `python -m py_compile app.py` passes | Reviewer re-ran `py_compile`, `docker build`, confirmed the `player_client` key is read by the installed yt-dlp extractor, and drove live downloads (previously-failing `LV-NXucnyrc`, plain MP3/Video, playlist-link, error-path) through the built Docker image — all passed; see `.ai/REVIEW.md` | none | | T-007 | `app.py` (`video720` mode: `Literal` type extension, `bestvideo[height<=720]+bestaudio/best[height<=720]` format branch, third HTML button) + `README.md` update | ready_for_implement | UI shows a third "Download Video 720p" button; downloads are capped at 720p with graceful fallback to lower quality when the source is below 720p; progress bar, auto-delivery, and sanitized filename behavior match existing modes; existing MP3/Video buttons unchanged; `python -m py_compile app.py` passes | pending | implement |