Story pipeline — events → a legible feed [Flow]
Source path: knowledge-base/diagrams/flows/story-pipeline.md
# Story pipeline — events → a legible feed `[Flow]`
Every Program task ([program-loop](../concepts/program-loop.md)) emits a canonical `DomainProgramEvent`. Turning those into an expert-forward feed is a **pure pipeline**: registry → editorial → projection → surfaces. Stories are a projection, never a second source of truth.
```mermaid
flowchart TB
Event["**DomainProgramEvent**<br/>kind · artifactRefs · salience · summary"]
Event --> Reg["**Registry** — STORY_KIND_REGISTRY<br/>channel · mode · queueClass · title · consequence"]
subgraph Ed["Editorial — two layers"]
direction TB
Floor["**voice floor** (deterministic)<br/>every kind gets a real headline"]
AI["**AI craft** (best-effort)<br/>verbatim quotes or dropped whole"]
Floor --> AI
end
Reg --> Floor
subgraph Proj["Projection — pure + deterministic"]
direction TB
Order["projectStories<br/>order: class → salience → time"]
Dedup["dedupStoryQueue<br/>collapse echoes"]
Readout["resolveStoryReadout<br/>sparklines · check dots · diffs"]
Order --> Dedup --> Readout
end
AI --> Order
Readout --> Surf(["Surfaces — StoryReader · Timeline · Deck<br/>+ mobile Stories bars"])
Surf -->|"act card → stage a Directive<br/>reminder → answer in place<br/>mark-read → caught-up"| Human(["the human judges"])
```
**Invariants**
- **The registry is the single source of per-kind facts.** `STORY_KIND_REGISTRY` (exhaustive over `ProgramEventKind`) fixes each kind's channel, mode, queueClass, title eyebrow, and consequence class; `storyChannel` / `storyTitle` read from it. *Channels ≠ tasks:* 4 tasks, but **7 channels** (reminder · research · monitor · opinion · tutor · project · canon).
- **Editorial guarantees a voice.** The core floor (`VOICE_REGISTER`) means every card has a real headline at birth. The AI pass verifies quotes verbatim against source markdown and is dropped whole if nothing survives (the card keeps its floor). Only Research / Opinion / Merge get AI enrichment; Position cards carry the floor.
- **Projection is pure.** One projection + one receipt hook (`useProgramStories`) feed every surface, so ordering / filtering / read-tracking can't drift between desktop and mobile. Cards segment into **Act** (pending decisions, importance-ranked) and **Read** (the broadcast, grouped by run); read receipts are per-member and durable.
**Where it lives:** `lib/core/program/stories/` (registry · projection · dedup · readout · channels), `lib/core/program/editorial/voice-floors.ts` (floor), `lib/server/program/editorial-orchestration.ts` + `lib/engine/program/editorial.ts` (AI), `features/program/` + `shell/mobile/` (surfaces).
> **Not yet shipped:** durable ProgramJournals (audit beyond the rolling caps) and the newsletter delivery layer.
Open on GitHubRaw Markdown source