# Task 16 — Review desk **Agent**: `page-migrator` · **Model**: **Codex** — highest defect risk **Depends on**: 06, 11, 13 · **Parallel with**: 15 **Worktree**: `.agents/scripts/worktree.sh start 16 page-review-desk` ## Goal `/skills-review/` → Astro. The most interactive page: search, filtering, lazy file fetching, markdown rendering, a client-side diff view, six URL params, and a live API call to `vote-service/`. ## The six query params are a public contract `?author=`, `?skill=`, `?view=`, `?file=`, `?compare=`, `?render=` — documented in the page footer and shared externally. All six must round-trip, and browser back/forward must restore state (`syncUrl` / `selectFromUrl` today). **Test every one manually.** A snapshot diff cannot catch a broken deep link. ## Islands The catalog + detail pane is genuinely interactive: `client:load` is justified here. The vote widget is `client:visible`. Everything else server-renders. ## vote-service integration `window.SKILLS_REVIEW_VOTE_API = 'https://ai-for-dummies-vote.marcospaulo.dev.br'` is set inline in `index.html` today. Either keep the global or move it to `PUBLIC_VOTE_API` — **if you move it, update `vote-service/README.md` in the same change**, since it documents the coupling. `ALLOWED_ORIGIN` on the deployed service is `https://netcracker.pages.marcospaulo.dev.br`. If the site's origin changes, the vote API breaks with a CORS error. It does not change in this plan — but verify after cutover. ## Asserted by verify.mjs Interaction tokens: `from './catalog.js'`, `from './files.js'`, `renderList`, `renderDetail`, `selectSkill`, `packageSummary`, `markdownHeadings`, `markdownToc`, `loadSelectedFile`, `schedulePackageSearch`, `fetchSource`, `packageSearchText`, `diffMarkup`, `diffRows`, `searchParams.set('compare')`, `markdownMarkup`, `syncUrl`, `selectFromUrl`, `URLSearchParams`, `navigator.clipboard`, `document.execCommand`. Plus the catalog count: `id:'` occurrences across both catalogs **must equal 24**. Same rule as task 15 — re-point with task 19, never delete. ## Watch for The markdown renderer is hand-rolled (`markdownMarkup`, `markdownHeadings`, `markdownToc`). Task 06 moves rendering to build time — but the **diff view needs raw source text**, not rendered HTML. Keep both available. ## Done when - [ ] All six query params round-trip; back/forward restores state - [ ] Search, filter, file tabs, preview, change lens, download, copy all work - [ ] Vote widget reaches the live API; CORS preflight succeeds - [ ] Snapshot diff empty; screenshots match; checklist complete - [ ] `pnpm run gate` green