commit 662f950e1de1bcbfd59cf9e2e9152b1e1fd298f7
parent a4f77c30bee93e9a25ede8b5082516408813b494
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Mon, 21 Sep 2026 13:32:12 -0400
plans: curated tags — no schema bump, site layer is presentation-only, four ops
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat:
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/plans/curated-tags.md b/plans/curated-tags.md
@@ -21,7 +21,9 @@ with her in chat.
(re-evaluated at index build; operator pins/suppresses exceptions), by **import from a umtool project**.
2. **One tag per kind**: `eva-collab` (on mic), `eva-in-chat`, `eva-topic`; filter is OR across chips.
3. **Vocabulary both corpus-wide and per site, like aliases** — corpus file authoritative for
- definitions AND assignments; the site file is presentation (relabel/hide/order/colour) + site-only rules.
+ definitions AND assignments; the site file is presentation ONLY (relabel/hide/order/colour). **Amended
+ 2026-09-21 during S1**: a site-layer rule can never tag a record — a record is shared by every site carrying
+ its channel — so rules bind only from the corpus file and the site tab offers no rule editor.
4. **Surfaces — all four**: export lists (channel + all-videos), export search, MCP filter, editor lists.
5. **Universal + flexible, three writers**: free-form tag ids for any subject, optional `group` so chips
read "Eva: Collab · In chat · Discussed"; operator UI, `pnpm ops` (agents; MCP stays read-only per
@@ -90,7 +92,8 @@ scope and date range are applied before compiling; each kind compiles once per b
video from the `cues`/`subs` sub-DBs (no disk re-read). Returns the changed `indexKey`s, which are unioned
into the dirty-channel set so transcript/subs/summaries pages rewrite — `common/lib/channelSignature.ts`
hashes only mtimes (FACTS ~:203-207), so this explicit dirtying is what keeps compose from skipping them.
- `SCHEMA_VERSION` 13 → 14 (`:143`). Build log prints `curated tags: rules <hash8> (changed), re-derived N`.
+ `SCHEMA_VERSION` stays **13** (amended during S1: an absent `curatedRulesHash` can never match, so the first
+ build re-derives every record from LMDB in ~80 s; a bump would re-read 76k video dirs for the same state). Build log prints `curated tags: rules <hash8> (changed), re-derived N`.
- **Counts**: while streaming `sums` into per-site summaries pages (`:1712`) accumulate per-tag totals and
per-channel breakdown → `tag-counts.json` in `siteIndexDir(paths, siteId)` (`common/lib/site.ts:138`).
- **Compose** (`common/bin/compose-site.ts:744-753`, beside aliases): `effectiveSiteTags(paths, siteId)` +
@@ -109,16 +112,16 @@ scope and date range are applied before compiling; each kind compiles once per b
`export/e2e/fixtures/data.ts` emits `curatedTags` on two summaries and a `/tags.json` fixture. Merge to
main immediately — S2 and S3 branch from it.
2. `common/lib/curatedTagsStore.ts` (mirror `common/lib/aliasesStore.ts`): `readGlobalTags/writeGlobalTags/
- readSiteTags/writeSiteTags/effectiveSiteTags` + **`applyTagAssignments(paths, {op: add|remove|replace, tag,
+ readSiteTags/writeSiteTags/effectiveSiteTags` + **`applyTagAssignments(paths, {op: add|remove|suppress|unsuppress, tag,
videos, source, at})`**; `paths.globalTagsFile` (`common/lib/paths.ts:105,219`), `siteTagsFile`
(`common/lib/site.ts:132`); tests: sanitize, layering, both-lists conflict, provenance.
3. `curatedTagsIndex.ts` + `buildIndex.ts` hook at `:697`, meta hashes, `reapplyCuratedTags`,
- `SCHEMA_VERSION` 14, per-site counts at `:1712`; `toDisplaySummary`. Measure rule cost on legal-mindset
+ NO schema bump (see Derivation), per-site counts at `:1712`; `toDisplaySummary`. Measure rule cost on legal-mindset
(478 chat streams) and record it in FACTS.
4. Contract + compose: `contract.ts` spec 4 + `ROOT_FILES`; `corpus.ts:204,:320`; `compose-site.ts:744-753`
writes `/tags.json`; `corpus.test.ts`.
5. `plans/FACTS.md` (the three meanings of "tags" in the naming-hazards table; chat-author prefix contract;
- the two meta hashes; SCHEMA_VERSION 14) + `AGENTS.md` (tags.json is curated data; never hand-edit).
+ the two meta hashes; SCHEMA_VERSION unchanged) + `AGENTS.md` (tags.json is curated data; never hand-edit).
### S2 — export UI + MCP (branch `tags/site`, needs only S1.1)
6. `common/lib/search/evalTree.ts`: `curatedTags?` on `SearchFilters` (`:311`) and `FilterableRecord`
@@ -146,7 +149,8 @@ scope and date range are applied before compiling; each kind compiles once per b
`previewTagRuleAction` = dry-run `evaluateTagRules` over LMDB `sums/cues/subs`, listing title/date/channel
with Pin all / Pin / Unpin, `applyTagAssignmentsAction`) — pattern `editor/app/sites/[siteId]/aliases/`.
Nav entry (twelve → thirteen; `editor/scripts/measure-nav.mjs`).
-13. Per-site overlay tab `editor/app/sites/[siteId]/tags/page.tsx` (presentation fields + site-only rules).
+13. Per-site overlay tab `editor/app/sites/[siteId]/tags/page.tsx` (presentation fields only — no rule editor,
+ see decision 3 as amended).
14. Video page `videos/[id]/components/TagsPanel.tsx` beside `OperationPanel` (`page.tsx:251`);
`toggleVideoTagAction` in `videoActions.ts` (shows each tag's provenance).
15. `VideoListPane.tsx`: `tag`/`untag` in `BULK_ACTION_OPTIONS` (`:38-49`) with a tag picker via