commit 0a2639b3dc1794f75c2ca458ef225da1e4f792ea
parent d75c63c989dcd750945c3101c086cf2d1e074e7f
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Thu, 1 Oct 2026 22:04:40 -0400
plans: slice T1's review, its fixes and the gates after them
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat:
1 file changed, 43 insertions(+), 13 deletions(-)
diff --git a/plans/release-17.md b/plans/release-17.md
@@ -382,8 +382,11 @@ option and the umtool twin; the mover and every editor surface are T2's.
2. The tier link carries the file's times (`lutimes`) and `normalizeLiveChat`/`isLiveChatCuesFresh` `lstat`
the raw replay: the raw is media now, and the index's freshness check would otherwise reach the media
drive per video.
-3. `normalizeLiveChat` tiers only when it wrote the cues (not on "fresh"), so an export build's normalize
- pass moves nothing.
+3. `normalizeLiveChat` tiers only when it wrote the cues (not on "fresh"). As first shipped this was
+ recorded as "an export build's normalize pass moves nothing", which was not true (`archiveLiveChat`
+ called it, so a build with stale cues tiered — and read — the raw); since the review `archiveLiveChat`
+ passes `tier: false`, so a build moves nothing. It still READS a stale raw replay through the link with
+ no channel guard (T2: treat the corpus-wide live-chat passes as media readers).
4. `normalizeAllLiveChat` (corpus-wide, no slug for `runManagedFunction`) skips a channel whose media is not
reachable — the plan's "`normalize-live-chat` refused".
5. `evictClipWindows` asks the text tier (`clips/` is never tiered) — its kind is in the flip list.
@@ -465,18 +468,18 @@ videos list would not show the audio until T2 lands.
| Commit | What |
|---|---|
-| `9e74dff0` | `common:` the classifier (`mediaTier.ts`) and the hook/deleter (`mediaTier-server.ts`) + tests |
-| `14870c6f` | `common:` the model — `mediaDir` (CHANNEL.md regenerated), `legacy`, the text guard, `isTextHeld`, the builds/snapshot/normalize/shards/eviction/digest batch on the text tier, the snapshot's three byte fields, `needsText` and the fourteen flips, `mediaOnly`; tests re-premised; the 28 T2 skips |
-| `18d4acb0` | `common, editor:` every media finalisation tiers (transcode, both outcome writes, the batch modes, live-chat normalize), every deleter derefs, the link carries the file's mtime |
-| `7779b40f` | `common, umtool:` `isChannelHeldForLane` + its test, `normalizeAllLiveChat`'s media guard, the flips pinned, the text-guard job test, the call-site hook tests, the cues twin as a text guard |
-| `4892ddc0` | `common, umtool:` `markerHoldsText` (the old mover's scope-less `…/data` marker holds the text), the hook writes nothing under a marker |
+| `1d228a79` | `common:` the classifier (`mediaTier.ts`) and the hook/deleter (`mediaTier-server.ts`) + tests |
+| `8335f151` | `common:` the model — `mediaDir` (CHANNEL.md regenerated), `legacy`, the text guard, `isTextHeld`, the builds/snapshot/normalize/shards/eviction/digest batch on the text tier, the snapshot's three byte fields, `needsText` and the fourteen flips, `mediaOnly`; tests re-premised; the 28 T2 skips |
+| `85180cd6` | `common, editor:` every media finalisation tiers (transcode, both outcome writes, the batch modes, live-chat normalize), every deleter derefs, the link carries the file's mtime |
+| `05275d86` | `common, umtool:` `isChannelHeldForLane` + its test, `normalizeAllLiveChat`'s media guard, the flips pinned, the text-guard job test, the call-site hook tests, the cues twin as a text guard |
+| `d56050ff` | `common, umtool:` `markerHoldsText` (the old mover's scope-less `…/data` marker holds the text), the hook writes nothing under a marker |
| this commit | `plans:` this section, FACTS ("Release 17 slice T1"), the editor changelog |
#### Gates (logs `$T/T1-*.log`)
-- **tsc** (all workspaces) clean at every commit; last at `4892ddc0`.
-- **common:** at `7779b40f` **2,529 passed, 0 failed, 28 skipped** (2,557; `main`'s 2,528-test run had 49
- failures on this branch's first pass, all re-premised or skipped as above). At `4892ddc0` 2,530 passed,
+- **tsc** (all workspaces) clean at every commit; last at `d56050ff`.
+- **common:** at `05275d86` **2,529 passed, 0 failed, 28 skipped** (2,557; `main`'s 2,528-test run had 49
+ failures on this branch's first pass, all re-premised or skipped as above). At `d56050ff` 2,530 passed,
1 failed, 28 skipped: the failure is `storageHealth.test.ts`'s "M4: a healthy 64-wide walk … at half the
budget" timing case under a machine load of 22–28 (other sessions); the file passes 36/36 twice in
isolation right after. New tests: `mediaTier.test.ts` 35, `mediaTier-server.test.ts` 16,
@@ -487,19 +490,46 @@ videos list would not show the audio until T2 lands.
`queue-lock.test.mjs` timing cases fail under load; the rerun is clean. **umtool `cues.test.mjs`:** 23
passed, 1 skipped (LIVE).
- **Build:** the capped editor build (`systemd-run --scope -p MemoryMax=6G`, `next build`): exit 0, 172 s,
- at `7779b40f`.
+ at `05275d86`.
- **e2e** (from the worktree root, `$T/T1-specs.txt`: maybe-missing, video-page, cleanup-holds,
- cleanup-actionable, auto-queue, digest, jobs-channel, channel-storage) at `7779b40f`: **78 passed, 5
+ cleanup-actionable, auto-queue, digest, jobs-channel, channel-storage) at `05275d86`: **78 passed, 5
failed, 8.9 min** (after 33.6 min in the queue). The 5 are all `channel-storage.spec.ts`, all the retired
layout reading `legacy`, as expected until T2 rebases the mover: "relocate a channel's media to another
root, and move it back" (:80), "the /channels bulk move queues one job per channel and skips the rest"
(:250), "a bulk move puts every job on one queue and skips a channel with nothing to move" (:391), "the
Storage panel moves to a location picked by name" (:484), "Sync all skips a channel whose media drive is
not mounted" (:1091 — now says `media legacy: … run archilyzer storage migrate-tier test-youtube`). Not
- re-run after `4892ddc0` (unit-covered; a marker rule the specs do not reach).
+ re-run after `d56050ff` (unit-covered; a marker rule the specs do not reach).
- **Privacy gate:** 0 added lines carry the user or host name (`git diff 7f4901f1`, counts only; the one
file the whole-file grep names is `plans/FACTS.md`, with the same count as on `main`).
- **Numbers tool:** none.
+#### Review (SHIP AFTER FIXES, 12 findings) and the fixes
+
+Every commit over `main..HEAD` was rewritten (`git filter-branch --msg-filter`, worktree only) so its
+trailer is the session's `Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>` + `Claude-Session`
+line (finding 12): tip `f3f23792` → `001e9de7`; the shas in the table above are the rewritten ones
+(`828dc1a2` → `98ef1772` is the first `plans:` commit).
+
+| Finding | Fix |
+|---|---|
+| H1 the index stats (and may read) a tiered live chat through its link | `263c8b17`: the scan's `subsMs` loop `lstat`s a tierable track; a stale-cues fallback on a tiered raw reads through `onDrive(mediaDir)` only while the media is `ok`/`in-place`, else keeps the cues the last build held; `6b795c67`: an EXDEV tier gives the copy the file's times (`stat` and `lstat` agree). New gate `buildIndex.test.ts` (k): a STALLED media drive (the location marked, every call through a link onto it hanging) with a tiered live chat — the index and the stats build complete, nothing held, the live-chat cues kept, no call on the drive. A mutation (a following `stat` in `subsMs`) makes it hang. |
+| L2 crash window between the two renames | `6b795c67`: the bytes are placed by hard link (same disk) or atomic copy and renamed into the tier, then ONE rename swaps the name — it always resolves; `tierVideoDir` removes a dead process's stray `.tierlink-<pid>`. Tests: one inode after a same-disk tier; a stray healed. |
+| L3 `removeMediaFile` derefs only into `media/<sameId>/` | `6b795c67`: any id under the channel's own `media/` (never out of it); the target's dir is dropped when it empties. Test. |
+| L4 the export build tiers the raw live chat | `95c9a82c`: `normalizeLiveChat({ tier: false })` from `archiveLiveChat`; deviation 3 corrected above (the build still READS a stale raw — for T2). |
+| L5 a move that starts mid-hook (for T2) | `6b795c67`: the marker is asked again after the bytes land and before the name changes; the tier's copy is removed if one stands. |
+| L6 a video-dir delete on an unmounted or stalled media tier | `95c9a82c`: `deleteOneVideoDir` refuses unless the channel's media is `ok`/`in-place`, and removes the tier's side through `onDrive(mediaDir)`, refusing with the drive's sentence when it does not answer — before the text is touched. |
+| L7 gates at the tip | re-gated below. |
+| N8 an in-place `media/` takes a watchdog slot | `6b795c67`: a real `media/` is answered from the corpus disk. |
+| N9 `totalTextBytes` counts containers and partials | `95c9a82c`: documented as everything on the corpus disk but `clips/` and the tier. |
+| N10 a shard save runs the tier sweep | `95c9a82c`: skipped when `saveShardOnly`. |
+| L11 records | `001e9de7`: FACTS and the changelog bullet say what the index does with a tiered live chat; the bullet says "Needs a rebuild and restart of the editor." and names the refused video delete. |
+
+**Gates at `001e9de7`** (logs `$T/T1-regate2.log`, `$T/T1-e2e-2.log`): tsc clean; common **2,535 passed,
+0 failed, 28 skipped** (2,563); editor unit 109/109; test:scripts 304 passed, 2 skipped; umtool
+`cues.test.mjs` 23 passed, 1 skipped; capped editor build exit 0, 101 s; e2e (the same 8 specs) **78 passed,
+5 failed, 8.2 min** (after 39 min in the queue) — the same five `channel-storage.spec.ts` cases (:80, :250,
+:391, :484, :1091), the old mover's layout reading `legacy`, nothing else red. Privacy: 0 added lines carry
+the user or host name.
## Rollout