commit 33d71745bac4ad981b724fe0c7bb123c8895221a
parent 6c507ab1b60be2cced0c5ce8b76b9ac724fd5c20
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Tue, 8 Sep 2026 02:08:48 -0400
plans: the Phase 1 record counts to the tip, and STATE.md names the two traps
The totals were 62a1de4..b64af6e, so they omitted 1b519f3 and the band-doubling
fix 9f2bbf9 that the same section describes: 62a1de4..6c507ab is 35 commits,
109 files, 9,956 insertions and 7,341 deletions (102 / 7,510 / 7,199 outside
plans/). The commit count follows in STATE.md, FACTS.md and one-core.md, and
operations/lanes.ts was 368 lines, not 370.
STATE.md now names the deletion condition beside the gates: the four legacy
pause fields go once the live settings.json carries all four held keys, and
backfill.held must then default TRUE, because sanitizeBackfill defaults
enabled: false and legacyGateHeld reads it inverted.
Prose: the transcription lane draws 2,754 today, not 882 — replaceAutoSubs is
true on the live policy and the opt-in bucket rides the tail of the draw; the
entry is the policy-free list. EXTERNAL_BAND_IDS is two because it is derived,
not because it is pinned. Two traps added to the 1.5 record: sanitizeMatch will
accept match.bucket: "transcription", and a regenerated snapshot carries each
bucket-lane id twice — trivial here, playlist-sized on a fresh channel.
One comment-only code edit, no behaviour: ChannelWork.operations still argued
that an operation id in `buckets` would be claimed by a catch-all that never
asked for it, which is now the deliberate design for the two bucket lanes.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat:
5 files changed, 64 insertions(+), 24 deletions(-)
diff --git a/common/jobs/autoQueuePolicy.ts b/common/jobs/autoQueuePolicy.ts
@@ -285,10 +285,20 @@ export type ChannelWork = {
// bucket name -> available video ids in that bucket
buckets: Record<string, string[]>;
// operation id -> reachable video ids for that operation, from
- // snapshot.backfill[op].ids. A SEPARATE map rather than more entries in
- // `buckets`, because `buckets` is walked as a priority-ordered union by every
- // leaf that names no bucket — an operation folded in there would be claimed
- // by a transcription catch-all that never meant to ask for it.
+ // snapshot.backfill[op].ids. A SEPARATE map for the OPERATION lanes, because
+ // it is a separate CLAIM SPACE: buildPendingByLeaf claims a video as
+ // `${operation}\0${id}`, which is what lets one video be pending for
+ // diarization AND for attribution-diarized at the same time. Folding those
+ // into `buckets` would collapse them into one claim and silently drop the
+ // second operation's work.
+ //
+ // THE BUCKET LANES DELIBERATELY GO THE OTHER WAY (slice 1.5). Their work list
+ // is also `snapshot.backfill[op].ids`, but it is projected into `buckets`
+ // under the operation's id, because on those lanes the operation and the
+ // bucket union are the SAME work — there is no second operation to keep
+ // apart, and sharing the bucket claim space is what stops a catch-all leaf
+ // re-claiming a video an explicit retry-bucket leaf already took. See
+ // defaultDrawsForPolicy and controller/autoRunner.ts buildChannelWork.
//
// Optional: every projection written before operations existed omits it, and
// a leaf naming an operation simply finds nothing.
diff --git a/plans/FACTS.md b/plans/FACTS.md
@@ -3379,7 +3379,7 @@ still read `true/false/false/false` through `isGateHeld`.
The whole-phase anchors. The slice-1.4 entry above stays as the detail on where a lane's
pause lives; this is everything else a session needs before touching dispatch. Branch
-`one-core/phase-1`, `7f294df` → head, 33 commits, unmerged, off Phase 0's `af2a360`. The
+`one-core/phase-1`, `7f294df` → `81a663f` plus a docs commit, 36 commits, unmerged, off Phase 0's `af2a360`. The
record with every divergence is `plans/one-core-phase-1.md`.
**The model in one sentence:** the LANE is the dispatch noun (a queue key, a policy tree, a
diff --git a/plans/STATE.md b/plans/STATE.md
@@ -4,7 +4,7 @@ The working memory for the local-AI derived-corpus work. Rewritten at the end of
session, before context is cleared. See [`README.md`](README.md) for the protocol.
**Last updated:** 2026-09-08 — **one-core Phase 1 shipped** on branch `one-core/phase-1`
-(`7f294df` → HEAD, 33 commits, not merged): **dispatch is one scheduler, and the lane is the
+(`7f294df` → `81a663f` plus a docs commit, 36 commits, not merged): **dispatch is one scheduler, and the lane is the
noun.** The slice-level record — every sha range, every divergence, both operator gates — is
[`one-core-phase-1.md`](one-core-phase-1.md); the umbrella is
[`one-core.md`](one-core.md) and the anchors are
@@ -40,7 +40,10 @@ scopes migrating into lane trees, both `enabled: false`.
`snapshot.backfill[op].ids` is where all four lanes' work lives; the runner reads it and
falls back to the same fold, which is the migration (nothing is regenerated).
`plans/tools/phase1-worklist-check.ts` checks all 68 live snapshots read-only: **OK**,
- download 9, transcription 882, zero already carrying an entry.
+ download 9, transcription 882, zero already carrying an entry. The 882 is the
+ POLICY-FREE work list; the transcription lane still draws **2,754** today, because the
+ live `autoQueue.transcription.replaceAutoSubs` is `true` and `defaultDrawsForPolicy`
+ appends `downloadedAutoSubsOnly` (1,872) at the tail of the draw.
**Two operator gates are outstanding, and one of them gates a merge.**
@@ -53,6 +56,11 @@ scopes migrating into lane trees, both `enabled: false`.
`backfill.allowRedownload` and the channel scope. As configured today it would re-fetch
audio for ~66,540 videos. The migration left the lane disabled; the tree's channel leaves
are the scope from now on.
+- **The four legacy pause fields go only once the live `settings.json` carries all four
+ `held` keys** — which happens on its first write through the editor. And when
+ `sanitizePolicy` finally defaults `held`, **backfill's must default `true`**:
+ `sanitizeBackfill` defaults `enabled: false` and `legacyGateHeld` reads that field
+ INVERTED, so a `held: false` default would silently un-hold the very lane Gate B fences.
**BLOCKER FOR ANY EDITOR e2e IN THE PRIMARY CHECKOUT, and it is not ours.**
`editor/content` is an untracked **symlink to `/home/user/Projects/recipe-content`** (made
@@ -415,7 +423,9 @@ nothing renders.
14. ~~**The transcode operation**~~ — **REMOVED 2026-08-30**, `904f1a9` → `f717a36`. Plan:
[`editor-transcode-removed.md`](editor-transcode-removed.md); census in FACTS "Verified
2026-08-30 — transcode: what it was, what stayed". The band question is closed by
- deletion; `EXTERNAL_BAND_IDS` is two for good.
+ deletion; `EXTERNAL_BAND_IDS` is two — and since one-core 1.5 it is two because it is
+ `EXTERNAL_OPERATIONS.map(o => o.id)`, so a third external pipeline would join the rail
+ by being declared rather than by editing that constant.
**Recommended next (editor IA).** The UI slices are done and the transcode band is no longer a
candidate. What is left is **Phase 6** and **slice 9**, which is gated on the sweep running in
diff --git a/plans/one-core-phase-1.md b/plans/one-core-phase-1.md
@@ -1351,14 +1351,17 @@ OK
and is never sorted. **Live impact zero — `partialDownloads` sums to 0 across
all 68 channels** — which is precisely why nothing but a test would have caught
it, and there is one.
-- **The transcription total is 882, not the 2,754 the brief expected.** 2,754 is
- the union with `replaceAutoSubs` ON: 881 `downloadedNoTranscript` + 1,872
- `downloadedAutoSubsOnly` + 1. The DEFAULT union is `downloadedNoTranscript` ∪
- `failedListed` = 881 + 25, and **24 of those 25 are already in the first list**,
- so the deduped answer is 882. The opt-in auto-captions bucket is a policy
- switch, not a corpus fact, and folding it into a snapshot entry would make
- `replaceAutoSubs` a property of the archive; it enters where it always has, at
- the TAIL of `defaultDrawsForPolicy`.
+- **The transcription ENTRY is 882, not the 2,754 the brief expected — and the
+ transcription LANE still draws 2,754 today.** Both numbers are right and they
+ are different measures. The entry is the policy-free work list:
+ `downloadedNoTranscript` ∪ `failedListed` = 881 + 25, and **24 of those 25 are
+ already in the first list**, so the deduped answer is 882. The live
+ `autoQueue.transcription.replaceAutoSubs` is **`true`**, so
+ `defaultDrawsForPolicy` appends `downloadedAutoSubsOnly` (1,872) at the TAIL of
+ the draw and the lane's actual pending set is 2,754 — which is exactly what the
+ numbers script has always printed and still prints. Folding the opt-in bucket
+ into a snapshot entry would make `replaceAutoSubs` a property of the ARCHIVE
+ rather than of the policy, which is why it enters where it always has.
- **The lane's work list is projected into `ChannelWork.buckets`, under the
operation's id — not into `.operations`.** This is the change that makes "no
number moves" true rather than merely intended. `buildPendingByLeaf` claims a
@@ -1456,13 +1459,27 @@ than as a re-reading of numbers copied out of an older build.
it predates 1.4 and 1.4 did not move it — and named here rather than fixed,
because the fix is a decision about what the /jobs strip means when the pool and
the file disagree, not a rename.
+- **`sanitizeMatch` accepts any bucket string**, so a hand-edited leaf carrying
+ `match.bucket: "transcription"` (or `"download"`) now draws that lane's WHOLE
+ work list instead of finding nothing. Unreachable from the UI — the bucket
+ select offers only `selectableBucketsForKind`, which does not include the
+ operation ids — and harmless where it is reachable, since the list is what a
+ bucket-less leaf on that lane draws anyway. Named because "a leaf naming
+ anything else finds no list" stopped being literally true for two strings.
+- **A regenerated snapshot carries each bucket-lane id twice** — once spread
+ across its buckets, once merged into `backfill.<lane>.ids`. Trivial on this
+ corpus (9 and 882 ids) and deliberate: the whole point is one array per lane.
+ It is not trivial for a FRESHLY ADDED channel, whose `undownloadedIds` is the
+ entire playlist, so a 30,000-video channel's first snapshot grows by 30,000
+ duplicated ids. If that ever bites, the fix is for the runner to fold rather
+ than for the entry to shrink — the entry is what makes the four lanes uniform.
- The 1.4 traps above all still stand, including the two greps
(`backfill.enabled` needs its own).
## Phase 1, as shipped
-`7f294df` → `2133d94` plus this commit, **33 commits on `one-core/phase-1`** off
-`af2a360` (Phase 0's head). Five slices:
+`7f294df` → `81a663f` plus this docs commit, **35 commits on `one-core/phase-1`**
+off `af2a360` (Phase 0's head) — 36 with this one. Five slices:
| slice | range | what it did |
|---|---|---|
@@ -1470,10 +1487,13 @@ than as a re-reading of numbers copied out of an older build.
| 1.2 | `83954f1` → `0438a72` | one `operationBatch.ts`; the runner runs operations on all four lanes |
| 1.3 | `253826b` → `451c454` | the two sweeps and the arbiter retire; ten settings fields migrate then go |
| 1.4 | `0040e39` → `1a4524b` | pause is `autoQueue[lane].held`, with the four legacy fields as a read-time fallback |
-| 1.5 | `4cb226e` → this commit | one work list per lane in the snapshot |
+| 1.5 | `4cb226e` → `81a663f` | one work list per lane in the snapshot |
-**107 files, 9,357 insertions, 7,284 deletions** (101 files / 7,441 / 7,198
-outside `plans/`). **Eighteen files deleted, 5,273 lines**: `backfillBatch.ts`
+**109 files, 9,956 insertions, 7,341 deletions** (102 files / 7,510 / 7,199
+outside `plans/`), measured `af2a360..81a663f` — the tip, not `2133d94`, so the
+two follow-ups this section describes (`a7922a3` and the band-doubling fix
+`d8754d2`) are counted. This docs commit adds one more file's worth of prose to
+the first figure and nothing to the second. **Eighteen files deleted, 5,273 lines**: `backfillBatch.ts`
937, `digestBatch.ts` 647, `backfillSweep.ts` 517, `SweepLane.tsx` 422,
`arbiter.ts` 416, `digestSweep.ts` 368, `sweepPreview.test.ts` 321,
`SweepPlan.tsx` 264, `backfillBatch.test.ts` 231 (renamed to
@@ -1482,7 +1502,7 @@ outside `plans/`). **Eighteen files deleted, 5,273 lines**: `backfillBatch.ts`
`OrderReach.tsx` 133, `ArbiterBar.tsx` 113, `arbiterWork.ts` 67,
`resume-backfill-sweep/route.ts` 35. Plus, in place: three job kinds, two boot
resume hooks, ten settings fields with their sanitizers and forms, four sweep
-server actions, the arbiter's two actions, and `operations/lanes.ts` at 370 → 131.
+server actions, the arbiter's two actions, and `operations/lanes.ts` at 368 → 131.
**Tests: common 876 → 908 (+32), mcp 205 → 205, e2e 511 → 515.**
`architecture.test.ts`'s allow-list **shrank by one** (`lib/sweepPlan.ts ->
diff --git a/plans/one-core.md b/plans/one-core.md
@@ -183,8 +183,8 @@ Makes the later deletions safe and cheap.
### Phase 1 — Dispatch: one scheduler (5 slices)
-**SHIPPED 2026-09-08** on branch `one-core/phase-1` (`7f294df` → head, 33 commits,
-unmerged, off Phase 0's `af2a360`), all five slices. The record — every slice's sha range,
+**SHIPPED 2026-09-08** on branch `one-core/phase-1` (`7f294df` → `81a663f` plus a docs
+commit, 36 commits, unmerged, off Phase 0's `af2a360`), all five slices. The record — every slice's sha range,
every divergence, both operator gates and the totals — is
[`one-core-phase-1.md`](one-core-phase-1.md); the anchors are
[`FACTS.md`](FACTS.md#one-core-phase-1-verified-2026-09-08). **No live number moved**, and