From 4c1ec6e02e8d60c98a6873d1d187140dec3c3522 Mon Sep 17 00:00:00 2001 From: Ben Stull Date: Thu, 4 Jun 2026 06:06:45 -0700 Subject: [PATCH] spec: fold in operator approval + pano-projector design change Operator approved the spec and confirmed first-ship archives (LibriVox + NASA + IA). Folds in the 2026-06-04 design change (single panoramic projector across all three walls, nature-video content): demotes dominant_color to optional/opt-in (its only consumer was the procedural side walls), ffmpeg-only when computed, never an image lib. Flags the design-spec/ROADMAP follow-up as out of scope here. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../2026-06-04-ingest-tagging-review-tools.md | 81 ++++++++++++------- 1 file changed, 53 insertions(+), 28 deletions(-) diff --git a/docs/superpowers/specs/2026-06-04-ingest-tagging-review-tools.md b/docs/superpowers/specs/2026-06-04-ingest-tagging-review-tools.md index f940769..29b180d 100644 --- a/docs/superpowers/specs/2026-06-04-ingest-tagging-review-tools.md +++ b/docs/superpowers/specs/2026-06-04-ingest-tagging-review-tools.md @@ -22,7 +22,8 @@ calls for (§5), under `tools/`: pool and write a catalog record. 2. **Mechanical tagging** — tooling auto-fills the non-curatorial fields: `mode` (via `ffprobe`), `license`/`attribution`/`source_*` (from origin), - `duration_s`, `resolution`, and `dominant_color` (computed from the video). + `duration_s`, `resolution`, and — optionally, opt-in only — `dominant_color` + (computed from the video; see §5.2 design-change note). 3. **Coordinate drafting** — a proposer suggests `left/right/dark/light` with a one-line `rationale`, written as `review_status: proposed`. 4. **Review CLI** — walks `proposed` records one at a time (proposed coords + @@ -193,29 +194,35 @@ derives: `tools/probe.py` takes the subprocess runner as an injectable dependency (default: `subprocess.run`); tests feed canned `ffprobe` JSON and never shell out. -### 5.2 `dominant_color` — computed from the video (`tools/mediatools.py`) +### 5.2 `dominant_color` — optional, deferred (computed from the video only on demand) -For `video`/`av` records, extract a representative frame mid-segment and reduce it -to one hex color. **Primary approach is `ffmpeg`-only** (keeps the dependency -surface to just `ffmpeg`/`ffprobe` — no image library): +> **Design-change note (2026-06-04):** `dominant_color`'s only consumer was the +> **procedural side walls** (design §7): hue for the three non-primary walls. The +> installation is moving to a **single panoramic projector that spans all three +> walls showing the real (nature-video) content**, which removes the procedural +> side-wall renderer — and with it the need to *compute* a dominant color. So this +> spec **demotes `dominant_color` from a core mechanical-tagging requirement to an +> optional, opt-in computation.** This is a knock-on of a larger design shift that +> primarily affects sub-projects 3 and 5 and the design spec (see §11 follow-up). -``` -# representative frame near the middle, reduced to a single-entry palette -ffmpeg -v quiet -ss -i -vf "thumbnail,palettegen=max_colors=1" -frames:v 1 -f rawvideo -pix_fmt rgb24 - -``` +Concretely: -The 3 output bytes are the dominant palette color → `"#rrggbb"`. (A simpler -`scale=1:1` average-color path is the fallback if `palettegen` is unavailable.) -Audio-only records keep `dominant_color=""`. +- The `dominant_color` **field stays** in the schema (it is already there; default + `""`) — no schema change either way. +- Ingest does **not** compute it by default. An opt-in flag + (`--dominant-color`) enables computation for `video`/`av` records, for the case + the operator still wants it (e.g. a later ambient/lighting use). +- **When enabled, it is `ffmpeg`-only — never an image library.** Extract a + representative mid-segment frame and reduce it to one hex color: + ``` + ffmpeg -v quiet -ss -i -vf "thumbnail,palettegen=max_colors=1" -frames:v 1 -f rawvideo -pix_fmt rgb24 - + ``` + The 3 output bytes are the dominant palette color → `"#rrggbb"` (a `scale=1:1` + average-color path is the fallback if `palettegen` is unavailable). This honors + the operator's "no video manipulation needed" steer: no Pillow, no new dep, and + the work isn't done at all unless explicitly requested. -> **Open decision (logged):** the roadmap assumed "an image lib for dominant -> color." This spec instead recommends the **ffmpeg-only** path so the whole -> sub-project depends on nothing beyond `ffmpeg`/`ffprobe`. **Pillow** (k-means / -> `quantize` over a sampled frame) is the documented fallback if ffmpeg-derived -> color quality proves insufficient in review. Chosen for the lean dependency -> story; reversible. - -`dominant_color` feeds the side walls (sub-project 5, design §7). +Audio-only records always keep `dominant_color=""`. ### 5.3 `license` / `attribution` / `source_*` — from origin (`tools/licensing.py`) @@ -469,8 +476,9 @@ Mirrors sub-project 1's TDD discipline (test-first, stdlib, hermetic). 2. **Mechanical tagging** — canned `ffprobe` JSON → expected `mode`/`duration_s`/ `resolution`; the **cover-art `attached_pic` guard** keeps an art-bearing MP3 at `mode="audio"`. -3. **Dominant color** — canned ffmpeg `rgb24` bytes → expected `"#rrggbb"`; - audio-only → `""`. +3. **Dominant color (opt-in path)** — with the flag on, canned ffmpeg `rgb24` + bytes → expected `"#rrggbb"`; with the flag off (default), `dominant_color` + stays `""`; audio-only → `""`. 4. **License normalization** — sample per-archive metadata → correct `license`; `cc_by`/`cc_by_nc` produce non-empty `attribution`; unmappable license is rejected. @@ -504,13 +512,17 @@ fixture clip → `mode`/`duration`/`resolution`; real dominant-color extraction. None block writing the implementation plan; each has a recommended default the plan will assume unless the operator overrides. -1. **Dominant-color dependency** — *Recommend:* ffmpeg-only (`palettegen`), no - image lib; Pillow as fallback. (Roadmap had assumed an image lib.) +1. **Dominant-color dependency** — *Decided (operator, 2026-06-04):* `dominant_color` + is **optional / opt-in** and, when computed, **ffmpeg-only — no image lib**, + because the move to a single panoramic projector showing real nature video + removes the procedural side walls that were its only consumer (§5.2). 2. **`file_path` style** — *Recommend:* relative-to-`media-root` for portability; reconcile the USER_GUIDE's absolute examples with a doc note; player spec defines mount resolution. -3. **Which archives ship first** — *Recommend:* LibriVox, NASA, Internet - Archive/Prelinger first; defer Freesound, Musopen, FMA (auth / API-stability tax). +3. **Which archives ship first** — *Decided (operator, 2026-06-04):* **LibriVox, + NASA, Internet Archive/Prelinger** first; defer Freesound, Musopen, FMA (auth / + API-stability tax). (Nature-video content focus weights NASA/IA; the audio + pools still serve the catalog's audio modes.) 4. **CLI surface** — *Recommend:* two `python -m` entry points (`tools.ingest_cli`, `tools.review_cli`), matching the no-install repo convention; console-script aliases optional. @@ -522,14 +534,27 @@ archive-identifier field, `media_sha256` integrity, an `ingested_at` timestamp, any LLM-backed proposer in the core. All are future, additive extensions; none are needed for the done-criteria. +**Design-spec follow-up (beyond this sub-project):** the operator's 2026-06-04 +decision to use a **single panoramic projector spanning all three walls, showing +real nature video**, supersedes the design spec's §6 (four projectors) / §7 +(procedural side-wall renderer) and reshapes sub-projects **3** (player drives one +pano output, not primary + side feed) and **5** (procedural side walls likely +dropped). The design spec +(`2026-06-04-human-experience-filter-design.md`) and ROADMAP should be updated to +reflect this in a separate pass; it is **out of scope for the sub-project-2 spec**, +whose only affected element is the now-optional `dominant_color` (§5.2). + --- ## 12. Relationship to the other sub-projects - **Consumes** sub-project 1 (`hef.catalog`, `hef.selection`) — the only required change is the additive `validate_catalog` (+ optional `index_by_id`), §3. -- **Feeds** sub-project 3 (the Pi player): a populated, `approved` catalog with - `dominant_color` ready for sub-project 5's side walls. The player resolving +- **Feeds** sub-project 3 (the Pi player): a populated, `approved` catalog the + player drives to the (now single, panoramic) projector. The player resolving `file_path` against its drive mount (§6.3) is a player-spec concern. +- **Side walls (sub-project 5)** are likely **dropped** under the pano-projector + design change (§11 follow-up); `dominant_color`, their only input, is + correspondingly optional here (§5.2). - **Settles** two roadmap open decisions (download/caching layout §6.3; ingest language = Python under `tools/`, §4).