docs(audit): Phase 1 — reconcile stale checkboxes + fix roadmap drift

Tick items whose root cause already landed, and fix two doc-drift items:

- L82: align ROADMAP-PINCHFLAT Phase F Source/MediaItem sketch to the shipped
  shared/ipc.ts shape (videoId/itemCount/watched/feedUrl + required
  url/playlistTitle/playlistIndex).
- L89: note H8's afterAllArtifactBuild checksum hook fixes release-artifact
  consistency going forward; stale dist artifacts handled by L84.
- Tick the wire-or-remove trio (M5/M6/UX1 — all wired in the DownloadBar
  Advanced panel) and MAX_ENQUEUE_BATCH (M33 fixed the false comment).
- Tick UX ref-duplicates resolved by their roots (UX10=H5, UX13=M22, UX14=L76,
  UX25=L78), the (ref) a11y line (UI33/UI30/UI28/UI29 all done), and the
  (OK)/(non-goal) Windows-conventions line.

Docs only; no code touched. 149 -> 137 open audit items.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-01 08:36:51 -04:00
parent 6a9856b590
commit 4dfb3c9867
2 changed files with 51 additions and 27 deletions
+41 -24
View File
@@ -631,9 +631,12 @@ token system + shared primitives (UI/SIMP — high value, larger effort) · i18n
emitted "in `buildArgs` (`src/main/download.ts`)" — `buildArgs` lives in `src/main/buildArgs.ts`. emitted "in `buildArgs` (`src/main/download.ts`)" — `buildArgs` lives in `src/main/buildArgs.ts`.
- [x] **L81 — ROADMAP internal contradiction.** Phase A: "`--split-chapters` still TODO"; Phase L: - [x] **L81 — ROADMAP internal contradiction.** Phase A: "`--split-chapters` still TODO"; Phase L:
`[x]` split-chapters done. Phase A wasn't updated when L landed. `[x]` split-chapters done. Phase A wasn't updated when L landed.
- [ ] **L82 — PINCHFLAT roadmap interface sketches are stale.** [ROADMAP-PINCHFLAT.md](ROADMAP-PINCHFLAT.md) - [x] **L82 — PINCHFLAT roadmap interface sketches are stale.** [ROADMAP-PINCHFLAT.md](ROADMAP-PINCHFLAT.md)
Phase F's `Source`/`MediaItem` code blocks omit shipped fields (`videoId`, `itemCount`, Phase F's `Source`/`MediaItem` code blocks omit shipped fields (`videoId`, `itemCount`,
`watched`, `feedUrl`) — design sketches that drifted from `shared/ipc.ts`. `watched`, `feedUrl`) — design sketches that drifted from `shared/ipc.ts`. *Fixed: the Phase F
sketch now carries the shipped `videoId`/`itemCount`/`watched`/`feedUrl` fields (plus the
required `url`/`playlistTitle`/`playlistIndex`) and a note that the block reflects the shipped
`shared/ipc.ts` shape.*
- [ ] **L83 — Dead build artifacts.** electron-builder emits `.blockmap` differential-update files - [ ] **L83 — Dead build artifacts.** electron-builder emits `.blockmap` differential-update files
for each NSIS installer, but the custom [updater.ts](src/main/updater.ts) does a full download and for each NSIS installer, but the custom [updater.ts](src/main/updater.ts) does a full download and
never consumes them. never consumes them.
@@ -648,8 +651,12 @@ token system + shared primitives (UI/SIMP — high value, larger effort) · i18n
only; the post-processing `DownloadOptions` used originally are lost (current defaults apply). only; the post-processing `DownloadOptions` used originally are lost (current defaults apply).
- [x] **L88 — `applyEvent('progress')` can promote a `queued` item to `downloading`** outside - [x] **L88 — `applyEvent('progress')` can promote a `queued` item to `downloading`** outside
`pump()` — a latent concurrency edge if a progress event ever arrives before/without the launch transition. `pump()` — a latent concurrency edge if a progress event ever arrives before/without the launch transition.
- [ ] **L89 — Inconsistent release artifacts.** Only `0.4.1` carries `.sha256` files (hand-made) and - [x] **L89 — Inconsistent release artifacts.** Only `0.4.1` carries `.sha256` files (hand-made) and
the version sequence skips 0.3.x — symptomatic of the manual release process behind H8. the version sequence skips 0.3.x — symptomatic of the manual release process behind H8. *Fixed at
the root by H8: [scripts/generate-checksums.cjs](scripts/generate-checksums.cjs) (electron-builder
`afterAllArtifactBuild` hook) writes a `.sha256` next to every built `.exe` and returns them for
upload, so future releases are consistent automatically; the stale pre-H8 `dist/` artifacts are
pruned by L84. (The historical 0.3.x version gap is immutable.)*
*Round 5 (2026-06-29) — code-level micro-inconsistencies & polish:* *Round 5 (2026-06-29) — code-level micro-inconsistencies & polish:*
@@ -1084,17 +1091,19 @@ root cause is already filed.
- [ ] **UX9 — No global completion feedback off the Downloads tab** (UI25). If OS notifications are - [ ] **UX9 — No global completion feedback off the Downloads tab** (UI25). If OS notifications are
off/suppressed (focus assist) and you're on another tab, a finished download gives no in-app sign. off/suppressed (focus assist) and you're on another tab, a finished download gives no in-app sign.
**Fix:** a sidebar Downloads badge / lightweight in-app toast. **Fix:** a sidebar Downloads badge / lightweight in-app toast.
- [ ] **UX10 — Re-download silently changes quality** (H5) — a confusing "I asked for 720p, got Best." - [x] **UX10 — Re-download silently changes quality** (H5) — a confusing "I asked for 720p, got Best." *Resolved by H5 (re-download stores `formatId`/`formatHasAudio` and strips compound quality labels).*
- [ ] **UX11 — Scheduled downloads silently never fire if the app is quit** (M4). The hint is easy to - [ ] **UX11 — Scheduled downloads silently never fire if the app is quit** (M4). The hint is easy to
miss; the user returns to find nothing happened. **Fix:** warn at schedule time that it requires the miss; the user returns to find nothing happened. **Fix:** warn at schedule time that it requires the
app running (or persist + relaunch). app running (or persist + relaunch).
- [ ] **UX12 — Terminal is a dead-end when custom commands are off** (L18). The nav item is always - [ ] **UX12 — Terminal is a dead-end when custom commands are off** (L18). The nav item is always
visible; clicking it shows a gate pointing to a setting on another screen. **Fix:** hide/disable the visible; clicking it shows a gate pointing to a setting on another screen. **Fix:** hide/disable the
nav item, or let the gate enable the setting inline. nav item, or let the gate enable the setting inline.
- [ ] **UX13 — Backup export warns of nothing; it contains secrets** (M22). A user "backs up settings" - [x] **UX13 — Backup export warns of nothing; it contains secrets** (M22). A user "backs up settings"
and ships proxy creds / tokens in cleartext. **Fix:** warn, or mask/omit secrets. and ships proxy creds / tokens in cleartext. **Fix:** warn, or mask/omit secrets. *Resolved by M22
- [ ] **UX14 — Duplicate warning can show a placeholder title** (L76): 'Already in your queue: (backup strips proxy / PO-token / update-token; the caption states credentials aren't included).*
- [x] **UX14 — Duplicate warning can show a placeholder title** (L76): 'Already in your queue:
"YouTube video (abc123)"' before metadata resolves looks broken. **Fix:** fall back to the URL. "YouTube video (abc123)"' before metadata resolves looks broken. **Fix:** fall back to the URL.
*Resolved by L76 (the dup warning falls back to the URL when the title is still the placeholder).*
- [ ] **UX15 — No bulk actions in the Downloads queue.** History has a select-mode + bulk delete; - [ ] **UX15 — No bulk actions in the Downloads queue.** History has a select-mode + bulk delete;
Downloads has only per-row remove + "Clear finished." Inconsistent. **Fix:** mirror select/bulk, or Downloads has only per-row remove + "Clear finished." Inconsistent. **Fix:** mirror select/bulk, or
add "Cancel all." add "Cancel all."
@@ -1118,8 +1127,9 @@ root cause is already filed.
- [ ] **UX23 — Settings folder paths are read-only** (L71) — no paste; Browse-dialog only. - [ ] **UX23 — Settings folder paths are read-only** (L71) — no paste; Browse-dialog only.
- [ ] **UX24 — "Check N watched for new" is disabled with no explanation** when no source is watched — - [ ] **UX24 — "Check N watched for new" is disabled with no explanation** when no source is watched —
a user with indexed (but unwatched) sources sees a dead button. **Fix:** tooltip / enable with a hint to watch a source. a user with indexed (but unwatched) sources sees a dead button. **Fix:** tooltip / enable with a hint to watch a source.
- [ ] **UX25 — Empty-state copy mismatches the flow** (L78): Downloads says "Paste a URL above to get - [x] **UX25 — Empty-state copy mismatches the flow** (L78): Downloads says "Paste a URL above to get
started," but the actual path is Fetch/Download. started," but the actual path is Fetch/Download. *Resolved by L78 (DownloadsView empty-state copy
rewritten to match the Fetch/Download flow).*
- [ ] **UX26 — yt-dlp/ffmpeg version + initial settings load have no skeleton/spinner** — brief blank - [ ] **UX26 — yt-dlp/ffmpeg version + initial settings load have no skeleton/spinner** — brief blank
states on boot (plus the documented one-frame theme flash). **Fix:** lightweight loading states. states on boot (plus the documented one-frame theme flash). **Fix:** lightweight loading states.
@@ -1225,16 +1235,16 @@ DPI handled by Chromium). The deviations:
`Badge`s (Fluent supplies its own forced-colors handling) and the thumbnail tints are purely decorative `Badge`s (Fluent supplies its own forced-colors handling) and the thumbnail tints are purely decorative
placeholders, so both correctly let the system palette win. Live verification under each Contrast theme is placeholders, so both correctly let the system palette win. Live verification under each Contrast theme is
still worthwhile but the color-meaning surfaces are now defended in code.* still worthwhile but the color-meaning surfaces are now defended in code.*
- [ ] **(ref) No semantic headings / radiogroup arrow-nav / focus rings** — UI33, UI30, UI2829 (all bear on Narrator + keyboard users). - [x] **(ref) No semantic headings / radiogroup arrow-nav / focus rings** — UI33, UI30, UI2829 (all bear on Narrator + keyboard users). *All four resolved (see UI33/UI30/UI28/UI29).*
### Settings & standard conventions (mostly OK) ### Settings & standard conventions (mostly OK)
- [x] **W19 — Window/taskbar don't reflect state.** No window title at all (L108), so the taskbar button - [x] **W19 — Window/taskbar don't reflect state.** No window title at all (L108), so the taskbar button
never shows "3 downloading" or similar. **Standard:** reflect activity in the title/tooltip. never shows "3 downloading" or similar. **Standard:** reflect activity in the title/tooltip.
- [ ] **(OK)** Per-user no-admin install, NSIS uninstaller, `aerofetch://` registration, AppUserModelID, - [x] **(OK)** Per-user no-admin install, NSIS uninstaller, `aerofetch://` registration, AppUserModelID,
tray tooltip + left-click restore + right-click menu, taskbar progress, and jump list all follow tray tooltip + left-click restore + right-click menu, taskbar progress, and jump list all follow
Windows conventions. **(Non-goal)** unsigned binary → SmartScreen prompt — accepted; no certificate will Windows conventions. **(Non-goal)** unsigned binary → SmartScreen prompt — accepted; no certificate will
be purchased (the build stays signing-ready via env vars if that ever changes — see [SIGNING.md](docs/SIGNING.md)). be purchased (the build stays signing-ready via env vars if that ever changes — see [SIGNING.md](docs/SIGNING.md)). *(Acknowledged — verified-OK / accepted non-goal, no action.)*
--- ---
@@ -1339,16 +1349,23 @@ filed. Several listed categories are **N/A** to this stack and worth recording s
- [x] **Safe to remove now — `getDefaultFolder`** (M2): channel + preload method + main handler + mock, - [x] **Safe to remove now — `getDefaultFolder`** (M2): channel + preload method + main handler + mock,
**zero callers**. Pure deletion, no behavior change. **zero callers**. Pure deletion, no behavior change.
- [ ] **Decide "wire or remove" — command preview** (M5): channel + preload `previewCommand` + main - [x] **Decide "wire or remove" — command preview** (M5): channel + preload `previewCommand` + main
`previewCommand()` + `formatCommandLine`/`quoteForDisplay` (buildArgs, **unit-tested**) + `previewCommand()` + `formatCommandLine`/`quoteForDisplay` (buildArgs, **unit-tested**) +
`CommandPreviewResult` + mock. Either surface it (UX1's per-download panel) or delete the whole chain (and its tests). `CommandPreviewResult` + mock. *Decided: **wired** (M5/UX1) — the DownloadBar Advanced panel has a
- [ ] **Decide "wire or remove" — incognito/private** (M6): `DownloadItem.incognito` + `AddOptions.incognito` Show/Hide command toggle calling `window.api.previewCommand`; the whole chain is now reachable.*
+ `buildItem` handling + two history-skip checks + the QueueItem "Private" badge. No UI sets it. Add a toggle or strip the plumbing. - [x] **Decide "wire or remove" — incognito/private** (M6): `DownloadItem.incognito` + `AddOptions.incognito`
- [ ] **Decide "wire or remove" — per-download options/extraArgs** (UX1): `DownloadItem.options`/`extraArgs`, + `buildItem` handling + two history-skip checks + the QueueItem "Private" badge. *Decided: **wired**
(M6/UX1) — the DownloadBar Advanced panel has an "Incognito mode" checkbox that sets the flag (reset
after each download).*
- [x] **Decide "wire or remove" — per-download options/extraArgs** (UX1): `DownloadItem.options`/`extraArgs`,
`StartDownloadOptions.options`/`extraArgs`, `AddOptions.options`/`extraArgs` are plumbed end-to-end but `StartDownloadOptions.options`/`extraArgs`, `AddOptions.options`/`extraArgs` are plumbed end-to-end but
never set by any UI. Largest block of built-but-unreachable code — wire the panel or remove the fields. never set by any UI. *Decided: **wired** (UX1) — the collapsible Advanced panel reuses
- [ ] **Comment, not code — `MAX_ENQUEUE_BATCH`** (M33): referenced by ipc.ts:629 + the roadmap but never `DownloadOptionsForm` for per-download overrides passed via `AddOptions.options`; overrides reset to
implemented; fix the comment (nothing to delete). the global defaults after each download.*
- [x] **Comment, not code — `MAX_ENQUEUE_BATCH`** (M33): referenced by ipc.ts:629 + the roadmap but never
implemented; fix the comment (nothing to delete). *Resolved by M33: the false `MAX_ENQUEUE_BATCH`
reference is gone; [ipc.ts](src/shared/ipc.ts):730 now honestly states all selected entries are
enqueued at once (with a note to add a cap if large — the actual cap is deferred to PERF3).*
**New cleanliness findings:** **New cleanliness findings:**
@@ -1386,9 +1403,9 @@ installer handoff `1500`, tickers `650`/`15_000`, stderr tail `4000`; magic stri
1. **Now (zero risk):** the `getDefaultFolder` slice (M2); un-export `PROGRESS_TEMPLATE` + `getManagedBinDir` (CL5). 1. **Now (zero risk):** the `getDefaultFolder` slice (M2); un-export `PROGRESS_TEMPLATE` + `getManagedBinDir` (CL5).
2. **Now (housekeeping):** prune `dist/` to the current release (L84); the macOS-only branches if Windows-only is committed (L147). 2. **Now (housekeeping):** prune `dist/` to the current release (L84); the macOS-only branches if Windows-only is committed (L147).
3. **Decision required (don't silently delete — these are documented features):** command preview (M5), 3. **Decision made — wired, not deleted (all resolved):** command preview (M5), incognito (M6), and
incognito (M6), and per-download options/extraArgs (UX1) — each is "wire it or remove it." Given UX1 per-download options/extraArgs (UX1) are now surfaced in the DownloadBar Advanced panel, so the
rates the per-download panel as high value, wiring is likely better than deleting. previously-unreachable plumbing is reachable. Nothing to delete.
4. **Not removable (intentional):** preview seed/mock data + `PREVIEW` branches (C1/L128) — they power the 4. **Not removable (intentional):** preview seed/mock data + `PREVIEW` branches (C1/L128) — they power the
browser-preview dev workflow; consolidate (C1) rather than delete. browser-preview dev workflow; consolidate (C1) rather than delete.
+10 -3
View File
@@ -109,19 +109,26 @@ yet. This is the prerequisite for every later phase.
channel?: string channel?: string
addedAt: number addedAt: number
lastIndexedAt?: number lastIndexedAt?: number
itemCount: number // cached MediaItem count for list display
watched?: boolean // included in scheduled / startup sync (Phase J)
feedUrl?: string // YouTube RSS feed for cheap "anything new?" checks
} }
interface MediaItem { interface MediaItem {
id: string // yt-dlp video id — the dedup key id: string // globally unique, `${sourceId}:${videoId}`
sourceId: string sourceId: string
videoId: string // yt-dlp video id — the dedup key within a source
title: string title: string
playlistTitle?: string // for the folder path; 'Uploads' fallback url: string
playlistIndex?: number // 1-based, for NNN numbering playlistTitle: string // for the folder path; 'Uploads' fallback
playlistIndex: number // 1-based, for NNN numbering
durationLabel?: string durationLabel?: string
downloaded: boolean downloaded: boolean
downloadedAt?: number downloadedAt?: number
filePath?: string filePath?: string
} }
``` ```
*(This block reflects the shipped `src/shared/ipc.ts` shape; the original sketch
predated the `videoId`/`itemCount`/`watched`/`feedUrl` fields.)*
- [x] **Dedup on index.** A video appearing in multiple playlists collapses to one `MediaItem` - [x] **Dedup on index.** A video appearing in multiple playlists collapses to one `MediaItem`
(keyed by video id); first playlist seen wins the folder assignment (surface this choice (keyed by video id); first playlist seen wins the folder assignment (surface this choice
in the UI so the user can reassign). The "Uploads" synthetic playlist catches anything in in the UI so the user can reassign). The "Uploads" synthetic playlist catches anything in