Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ jobs:
- name: Build
run: bun run build

- name: Comic loop tests
run: bun run test:comic-loops

- name: Contract tests
run: bun run test:contracts

Expand Down
36 changes: 21 additions & 15 deletions COMIC-README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ A daily webcomic featuring:
- 🧨 **Simon**: BOFH sysadmin who loves chaos
- 🐱 **The Cat**: Breaks the robot's reasoning

Each day, **two different AI models** generate a comic from the same prompt. Readers **vote** for their favorite variant!
Each day, a loop-engineered writers room builds a technical brief, ranks several joke premises, and gives **two different AI models** distinct premise mechanisms. Readers **vote** for their favorite variant.

## Features

Expand Down Expand Up @@ -41,7 +41,8 @@ Backend (Cloudflare)
└─ Web Push (Notifications)

Generation Pipeline
├─ comic-generator.ts (Prompt → Script)
├─ comic-loop.ts (Brief → Premises → Score → Retry/Invert)
├─ comic-generator.ts (Selected Premise → Script/Rewrite)
├─ svg-renderer.ts (Script → SVG)
└─ _worker.js (Orchestration)
```
Expand All @@ -58,12 +59,14 @@ Generation Pipeline

## Comic Format

4-panel strip with consistent structure:
Three or four panels with a consistent compositional contract:

**Panel 1**: Setup (Human asks question)
**Panel 2**: Robot internal reasoning (monospace thought bubble)
**Panel 3**: Robot response (speech bubble)
**Panel 4**: Punchline (usually Simon's deadpan comment)
**Contract**: Establish the reasonable expectation.
**Interpretation**: Reveal how the system optimized the requirement.
**Exposure**: Show the difference between the proxy and the intent.
**Optional reframe**: Change the target or reinterpret the setup.

Robot internal reasoning is optional. Exact dashboard, diff, alert, log, or terminal text is rendered deterministically through `screenText` when it carries the visual joke.

## Example Comic

Expand All @@ -74,21 +77,22 @@ Panel 1:
Human: "Robot, explain Kubernetes simply."

Panel 2:
Robot thought bubble:
> request detected
> user comprehension estimate: low
> generating analogy
Screen: `tests/evals.json — SCORE 100%`
Robot thought: `> answer key found`

Panel 3:
Robot: "It's like containers... but with more containers."
Human: "It memorized the repository."

Panel 4:
Simon (walking past): "Accurate."
Simon: "Promote grep. It's cheaper."
```

## Recurring Themes

- AI hallucinations and confidence
- Proxy metrics and specification gaps
- Agent permissions and approval theatre
- Eval contamination and automation incentives
- Prompt injection attacks
- Cloudflare product placement (subtle)
- DevOps disasters
Expand All @@ -99,8 +103,10 @@ Simon (walking past): "Accurate."
## Voting System

Each day presents two variants:
- **Variant A**: Generated by Model A (e.g., Llama 70B)
- **Variant B**: Generated by Model B (e.g., Mistral 7B)
- **Variant A**: Highest-ranked premise mechanism, generated by Model A
- **Variant B**: A distinct mechanism and target, generated by Model B

Drafts are scored for surprise, specificity, compression, visuality, character voice, and archive novelty. A failed draft gets one focused rewrite and, if still weak, one TRIZ inversion pass. See [workflows/comic-generation-loops.md](./workflows/comic-generation-loops.md).

Readers vote for:
- Better humor
Expand Down
3 changes: 3 additions & 0 deletions functions/api/test-generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ export async function onRequestPost(context: any) {
character_count: result.character_count,
topic_candidates: result.topic_candidates,
selected_topic: result.selected_topic,
brief: result.brief,
selected_premises: result.selected_premises,
script_evaluations: result.script_evaluations,
cast: result.cast,
models: {
a: result.model_a,
Expand Down
Loading
Loading