commit d0f084d9173ecd05001dcb6708e34ee9caa4f1cf
parent 88dbd41777e6925567821cc2b82af1b082c985b9
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Thu, 1 Oct 2026 22:50:02 -0400
plans: slice U1's review (SHIP AFTER FIXES), its fixes and the gates after them
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat:
1 file changed, 34 insertions(+), 0 deletions(-)
diff --git a/plans/release-17.md b/plans/release-17.md
@@ -498,4 +498,38 @@ project by a switch (slice U2); manifests, `revisions/`, the caches and the cue
`[Unreleased]` (`editor/CHANGELOG.md`): "umtool can keep each report's render folder on a media
drive." and "umtool's cache moves to `~/.cache/archilyzer/umtool`".
+#### Review (SHIP AFTER FIXES) and the fixes
+
+| Finding | Fix |
+|---|---|
+| F1 — the e2e app and the spec CLIs spread the shell's environment, so a shell exporting `UMTOOL_MEDIA_DIR` would put every fixture build's `out/` on the real media drive | `683e0a0f`: `UMTOOL_MEDIA_DIR=` (empty = unset under `\|\|`) in the webServer command; `UMTOOL_MEDIA_DIR: ""` in the `projects`, `report-longform` and `dashboard` CLI envs (`dashboard`'s doctor also gets the fixture cache); `storage.spec` keeps its own |
+| L1 — `doctor --json`'s `ok` was the tools' verdict while the exit status also counted the roots | `683e0a0f`: `ok = tools && roots`, `toolsOk` = the tools alone, `roots.ok` kept |
+| L2 — a CLI move cannot see the app's jobs | `683e0a0f`: `move-out`/`move-back` (one project or `--all`) skip, as `busy` with the pids, any project a running pipeline script (`build-video`, `check-availability`, `render-cards`, `compose-chrome`, `verify-build`, `fetch-via-editor`, `resolve-windows`, `cut-from-cache`, `share-batch`) names on its command line (`/proc/*/cmdline`; none elsewhere). It does not see the app's in-process deck previews; U2's in-app button can ask the app's jobs |
+| L3 — `dropMediaCopy` deleted any target inside "the media root", which untiered is the reports root | `a6926e17`: deletes only the project's own mirror, only when tiered and only when that is what came home; anything else is left and returned as `mediaCopyLeft` (the CLI prints "left in place … remove it by hand once checked"). A resumed move-back (the link already gone) reports the mirror, never deletes it |
+| L4 — a move-back cut after its rename orphaned the media copy silently | `a6926e17`: "already" reports the project's mirror as `mediaCopyLeft` while it exists |
+| L5 — a cut move's leftovers were not a guard | `a6926e17`: while `out.moved-*` or `out.incoming` exists, `ensureOutDir` (absent `out`) and both movers' directory branches refuse, naming the leftover and the move that finishes it; move-out refuses a lone `.incoming`, move-back a parked copy. `683e0a0f`: `folders.md` — the media root is a directory inside the drive, never the mountpoint; the leftovers rule |
+| N1 — the `paths.mjs` comment named the wrong reason for `READ_ROOTS` | `683e0a0f`: it names `/api/mix/{media,track}` and the lexical write check |
+| N2 — the walk did not skip `*.moved-*`/`*.incoming` | `683e0a0f`: `skipsDir` does |
+| N3 — `isMediaLink` realpathed every link it met | `683e0a0f`, `45cf9946`: only an entry named `out` (U2 adds its names to `MEDIA_LINKS`) |
+| N4 — the changelog bullet | `683e0a0f`: "in umtool's environment (restart umtool after setting it), to a directory inside that drive" |
+| N5 — an empty mirror for a project that does not exist | `a6926e17`: `ensureOutDir` checks the project directory first |
+
+`683e0a0f` left `report-to-video`'s tsc red (the `isMediaLink` parameter type); `45cf9946` restored it.
+
+**Gates after the fixes:** tsc clean at `45cf9946`. `storage.test.mjs` 24/24 (+4: the untiered
+hand-made link, a tiered foreign link, the leftovers guard both ways, the ghost project; the
+resumed-move-back case now expects the mirror reported and kept). `test:scripts` **394: 393 passed, 1
+skipped (LIVE), 0 failed**, `next-build-trace` passing against a fresh build. Capped umtool build with
+the corpus linked (76 channels; the fixes touch `storage.mjs`'s path ops): exit 0, 39 s, 0.83 GB.
+umtool e2e at `45cf9946`: `storage`, `projects`, `report-longform`, `dashboard` — **42 passed**, 1 failed, 2.3 min (after 45 min in the queue; `storage.spec` 5/5) — the one is `dashboard:14`, the run's first test, a 30 s timeout on the cold first page; `dashboard.spec.ts` alone right after: **7 passed**, 0 failed, 42 s.
+
+**Still left (follow-ups):** the project summary (`lib/projects/report.mjs`) stats `out/<slug>.mp4`
+and reads `out/availability.json` through the link, so a **stalled** media drive blocks those reads,
+libuv's threadpool and the project list, and `availability.json` — small hot text — now lives on the
+media tier; a dangling link still reads as "no build" there (`umtool check` learning it is U2's). The
+`usage.spec:112` order question (after the `triage` specs, at load) is for a quiet-machine run of
+`triage.spec.ts usage.spec.ts` at integration. If a song project ever grows an `out/` and is moved, a
+mix render into it lands on the media root through the link (the write check is lexical; that matches
+the semantics).
+
## Rollout