[object Object]

← back to Crazy News Channel

p24 daily-cartoons: docs for article-driven, still-image-by-default pipeline

8ef5d98e01612bb419ac1b00457bb9fe3794be1f · 2026-09-25 10:20:35 -0700 · Steve Abrams

README.md rewritten for TK-12237: article selection rules (14-day queue + full
manifest.js exclusion, real-news-first-then-p24-fallback), the new $0.003/cartoon
still-image cost line (was $0.103 with video), --concepts-only and --video usage,
and a note that the older multi-panel interactive-strip cartoons already in
cartoons/manifest.js use a different DOM than scripts/cartoon-shorts/make-cartoon-shorts.mjs
expects (pre-existing gap, unrelated to this change). run-daily.sh comment updated
to flag that --video must not be added there without an explicit Steve ask.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XizSgLiFuNbjY418z94Ewq

Files touched

Diff

commit 8ef5d98e01612bb419ac1b00457bb9fe3794be1f
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Fri Sep 25 10:20:35 2026 -0700

    p24 daily-cartoons: docs for article-driven, still-image-by-default pipeline
    
    README.md rewritten for TK-12237: article selection rules (14-day queue + full
    manifest.js exclusion, real-news-first-then-p24-fallback), the new $0.003/cartoon
    still-image cost line (was $0.103 with video), --concepts-only and --video usage,
    and a note that the older multi-panel interactive-strip cartoons already in
    cartoons/manifest.js use a different DOM than scripts/cartoon-shorts/make-cartoon-shorts.mjs
    expects (pre-existing gap, unrelated to this change). run-daily.sh comment updated
    to flag that --video must not be added there without an explicit Steve ask.
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01XizSgLiFuNbjY418z94Ewq
---
 daily-cartoons/README.md    | 62 +++++++++++++++++++++++++++++++++++----------
 daily-cartoons/run-daily.sh |  4 ++-
 2 files changed, 51 insertions(+), 15 deletions(-)

diff --git a/daily-cartoons/README.md b/daily-cartoons/README.md
index a836c68..2b2eee3 100644
--- a/daily-cartoons/README.md
+++ b/daily-cartoons/README.md
@@ -1,38 +1,72 @@
-# P24 daily editorial cartoons → local review queue (TK-12153)
+# P24 daily editorial cartoons → local review queue (TK-12153, article-driven TK-12237)
 
-4 classic-editorial-ink cartoons/day (cream #cdf5e0 / mint #0f9d78 duotone), each a
-poster + ~5s animated clip, written to a LOCAL queue for Steve to pick from.
+4 classic-editorial-ink cartoons/day (cream #cdf5e0 / mint #0f9d78 duotone), each a **still
+poster image** satirizing a real story from today's `real-news-data.js` (falling back to
+`stories-data.js`'s invented P24 stories when there aren't enough unused real articles),
+written to a LOCAL queue for Steve to pick from.
 **Nothing here publishes** to p24.agentabrams.com — approving only edits the local site tree.
 
 | Step | Engine | Cost |
 |---|---|---|
-| concepts (title, caption, image prompt, motion prompt) | local Ollama (`P24_CARTOON_OLLAMA_MODEL`, default Qwen2.5-Coder-32B) | $0 |
+| articles (pick 1 unused story per cartoon) | `real-news-data.js` + `stories-data.js` via `extract_stories.mjs` | $0 |
+| concepts (title, caption, image prompt — one gag per article) | local Ollama (`P24_CARTOON_OLLAMA_MODEL`, default Qwen2.5-Coder-32B) | $0 |
 | poster | Replicate `black-forest-labs/flux-schnell`, 4:3 jpg → PIL duotone | ~$0.003 |
-| clip | Replicate `wan-video/wan-2.2-i2v-fast`, 81 frames @ 16 fps (5.06 s), 480p | ~$0.10 (assumed rate) |
 
-~**$0.103/cartoon, ~$0.41/day** at N=4.
+~**$0.003/cartoon, ~$0.012/day** at N=4. Still image only — **no video/clip is generated by
+default.** A `--video` flag exists (adds a Replicate `wan-2.2-i2v-fast` 5s clip, ~$0.10/cartoon)
+but is **opt-in only** and is never passed by `run-daily.sh` or the launchd plist; do not add it
+there without an explicit Steve ask (Steve, verbatim, 2026-09-25: "just an image, not moving").
+
+## Article selection
+Each cartoon satirizes ONE real (or, as fallback, invented-P24) article, picked by
+`generate.py`'s `pick_articles()`:
+1. Skip any `story_id` already cartooned in the **last 14 days of the local queue**, or
+   **anywhere in `cartoons/manifest.js`** (full history, no day window).
+2. Prefer real news (`real-news-data.js`), newest first by parsed `publishedLabel`.
+3. Fall back to `stories-data.js`'s invented P24 stories only when real-news candidates run out.
+4. If there are 0 remaining candidates, the run reports it plainly and exits 1 — it never
+   silently reuses a story_id.
+
+Each concept is generated from that one article's headline + summary + tags — the prompt
+explicitly forbids naming or depicting any real person/party/company/brand/place/org from the
+article; invented anonymous figures only (`DENY` regex is a backstop, not the primary guard).
 
 ## Run
-    daily-cartoons/run-daily.sh [N]          # default N=4
-    open daily-cartoons/review.html          # review page (sort + size slider, created time, cost)
+    daily-cartoons/run-daily.sh [N]          # default N=4, still image only
+    python3 daily-cartoons/generate.py 4 --concepts-only   # articles + concepts only, $0, no Replicate calls
+    python3 daily-cartoons/generate.py 4 --video           # opt-in: also render a 5s clip per cartoon (~$0.10 ea)
+    open daily-cartoons/review.html          # review page (sort + size slider, created time, cost, linked article)
 
-Outputs: `queue/<date>/<slug>/{poster.jpg, clip.mp4, meta.json}` (meta = title, caption, prompts, cost, created_at, prediction ids).
+Outputs: `queue/<date>/<slug>/{poster.jpg, clip.mp4 (only with --video), meta.json}`.
+`meta.json` includes `story_id`, `story_title`, `story_url` (the real article link, or the
+site's own `index.html#/article/<id>` route for a P24-fallback story), `story_source`
+(`real-news` | `p24`), title, caption, prompts, cost, created_at, prediction ids.
 
 ## Cost guard
 `P24_CARTOON_CAP_USD` (default `1.00`) is a hard **daily** cap summed from `~/.claude/cost-ledger.jsonl`
 (`app=p24-daily-cartoons`, today's local date). Each cartoon starts only if its full estimate fits;
 each paid call is re-checked. Every paid call is logged via the cost-tracker skill (`log.js`).
-Exit codes: `0` ok · `1` error · `2` cap refused (e.g. `P24_CARTOON_CAP_USD=0 run-daily.sh 1` → exit 2, no spend).
+`--concepts-only` makes zero paid calls regardless of the cap.
+Exit codes: `0` ok · `1` error/no article candidates · `2` cap refused (e.g. `P24_CARTOON_CAP_USD=0 run-daily.sh 1` → exit 2, no spend).
 
 ## Approve (local only)
-    python3 daily-cartoons/approve.py <slug> --date YYYY-MM-DD --story-id <id> [--section politics]
+    python3 daily-cartoons/approve.py <slug> --date YYYY-MM-DD [--story-id <id>] [--section politics]
 Copies media into `cartoons/media/`, writes `cartoons/<date>-<slug>.html`, appends to `cartoons/manifest.js`.
-`--story-id` is required and must exist in `stories-data.js`/`real-news-data.js` (TK-12158 rule).
-Deploying to Kamatera stays a separate step Steve runs. Note: `*.mp4` is gitignored repo-wide.
+`--story-id` **defaults to the article the cartoon was generated from** (meta.json's `story_id`) and
+is still validated against `stories-data.js`/`real-news-data.js`; pass `--story-id` to override. A
+story_id is required either way (TK-12158 rule). Works with or without `clip.mp4` — poster-only
+cartoons render as a still `<img>`. Deploying to Kamatera stays a separate step Steve runs. Note:
+`*.mp4` is gitignored repo-wide.
 
 ## Schedule (NOT installed — paste to install; daily 07:23)
     cp ~/Projects/crazy-news-channel/daily-cartoons/com.steve.p24-daily-cartoons.plist ~/Library/LaunchAgents/ && launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.steve.p24-daily-cartoons.plist
 
 Remove: `launchctl bootout gui/$(id -u)/com.steve.p24-daily-cartoons`
 
-Distinct from the older text-strip pipeline (`scripts/daily-cartoon-gen.mjs`, `scripts/com.steve.p24-cartoons-daily.plist`), which only picks briefs from a bank.
+Distinct from the older text-strip pipeline (`scripts/daily-cartoon-gen.mjs`,
+`scripts/com.steve.p24-cartoons-daily.plist`), which only picks briefs from a bank, and from the
+older multi-panel interactive-strip cartoons already in `cartoons/manifest.js` (e.g.
+`commission-turtles`) built by a different, earlier generator — those have a `#strip`/`#nextBtn`
+DOM `scripts/cartoon-shorts/make-cartoon-shorts.mjs` expects; poster-only cartoons from THIS
+pipeline don't have that DOM and are not yet compatible with that Shorts script (pre-existing gap,
+not caused by --video defaulting off — see TK-12237 notes).
diff --git a/daily-cartoons/run-daily.sh b/daily-cartoons/run-daily.sh
index f3ed51c..23f4008 100755
--- a/daily-cartoons/run-daily.sh
+++ b/daily-cartoons/run-daily.sh
@@ -1,5 +1,7 @@
 #!/bin/bash
-# P24 daily editorial cartoons → LOCAL review queue (TK-12153). Never deploys.
+# P24 daily editorial cartoons → LOCAL review queue (TK-12153, article-driven TK-12237). Never deploys.
+# Still-image only by default (generate.py has no --video here on purpose — do not add it
+# without an explicit Steve ask; see daily-cartoons/README.md).
 # Usage: run-daily.sh [N=4]     env: P24_CARTOON_CAP_USD (default 1.00 daily hard cap)
 set -uo pipefail
 export PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin"

← fb5ea85 p24 daily-cartoons: review queue shows linked article, rende  ·  back to Crazy News Channel  ·  auto-data-snapshot: 2026-09-25T10:22:25 (2 data files) — .cl 9c5d41b →