feat: Add fast startup fetch and background caching

- Add  for quick startup using first N feeds
- Add background thread for full fetch and caching
- Update  to use fast fetch
- Update docs and skills
This commit is contained in:
2026-03-19 22:38:55 -07:00
parent 4f2cf49a80
commit 7eaa441574
13 changed files with 393 additions and 220 deletions

View File

@@ -2,136 +2,160 @@
## Architecture Overview
The Mainline pipeline uses a **Stage-based architecture** with **capability-based dependency resolution**. Stages declare capabilities (what they provide) and dependencies (what they need), and the Pipeline resolves dependencies using prefix matching.
```
Sources (static/dynamic) → Fetch → Prepare → Scroll → Effects → Render → Display
NtfyPoller ← MicMonitor (async)
Source Stage → Render Stage → Effect Stages → Display Stage
Camera Stage (provides camera.state capability)
```
### Data Source Abstraction (sources_v2.py)
### Capability-Based Dependency Resolution
- **Static sources**: Data fetched once and cached (HeadlinesDataSource, PoetryDataSource)
- **Dynamic sources**: Idempotent fetch for runtime updates (PipelineDataSource)
- **SourceRegistry**: Discovery and management of data sources
Stages declare capabilities and dependencies:
- **Capabilities**: What the stage provides (e.g., `source`, `render.output`, `display.output`, `camera.state`)
- **Dependencies**: What the stage needs (e.g., `source`, `render.output`, `camera.state`)
### Camera Modes
The Pipeline resolves dependencies using **prefix matching**:
- `"source"` matches `"source.headlines"`, `"source.poetry"`, etc.
- `"camera.state"` matches the camera state capability provided by `CameraClockStage`
- This allows flexible composition without hardcoding specific stage names
- **Vertical**: Scroll up (default)
- **Horizontal**: Scroll left
- **Omni**: Diagonal scroll
- **Floating**: Sinusoidal bobbing
- **Trace**: Follow network path node-by-node (for pipeline viz)
### Minimum Capabilities
## Content to Display Rendering Pipeline
The pipeline requires these minimum capabilities to function:
- `"source"` - Data source capability (provides raw items)
- `"render.output"` - Rendered content capability
- `"display.output"` - Display output capability
- `"camera.state"` - Camera state for viewport filtering
These are automatically injected if missing by the `ensure_minimum_capabilities()` method.
### Stage Registry
The `StageRegistry` discovers and registers stages automatically:
- Scans `engine/stages/` for stage implementations
- Registers stages by their declared capabilities
- Enables runtime stage discovery and composition
## Stage-Based Pipeline Flow
```mermaid
flowchart TD
subgraph Sources["Data Sources (v2)"]
Headlines[HeadlinesDataSource]
Poetry[PoetryDataSource]
Pipeline[PipelineDataSource]
Registry[SourceRegistry]
end
subgraph Stages["Stage Pipeline"]
subgraph SourceStage["Source Stage (provides: source.*)"]
Headlines[HeadlinesSource]
Poetry[PoetrySource]
Pipeline[PipelineSource]
end
subgraph SourcesLegacy["Data Sources (legacy)"]
RSS[("RSS Feeds")]
PoetryFeed[("Poetry Feed")]
Ntfy[("Ntfy Messages")]
Mic[("Microphone")]
end
subgraph RenderStage["Render Stage (provides: render.*)"]
Render[RenderStage]
Canvas[Canvas]
Camera[Camera]
end
subgraph Fetch["Fetch Layer"]
FC[fetch_all]
FP[fetch_poetry]
Cache[(Cache)]
end
subgraph Prepare["Prepare Layer"]
MB[make_block]
Strip[strip_tags]
Trans[translate]
end
subgraph Scroll["Scroll Engine"]
SC[StreamController]
CAM[Camera]
RTZ[render_ticker_zone]
Msg[render_message_overlay]
Grad[lr_gradient]
VT[vis_trunc / vis_offset]
end
subgraph Effects["Effect Pipeline"]
subgraph EffectsPlugins["Effect Plugins"]
subgraph EffectStages["Effect Stages (provides: effect.*)"]
Noise[NoiseEffect]
Fade[FadeEffect]
Glitch[GlitchEffect]
Firehose[FirehoseEffect]
Hud[HudEffect]
end
EC[EffectChain]
ER[EffectRegistry]
subgraph DisplayStage["Display Stage (provides: display.*)"]
Terminal[TerminalDisplay]
Pygame[PygameDisplay]
WebSocket[WebSocketDisplay]
Null[NullDisplay]
end
end
subgraph Render["Render Layer"]
BW[big_wrap]
RL[render_line]
subgraph Capabilities["Capability Map"]
SourceCaps["source.headlines<br/>source.poetry<br/>source.pipeline"]
RenderCaps["render.output<br/>render.canvas"]
EffectCaps["effect.noise<br/>effect.fade<br/>effect.glitch"]
DisplayCaps["display.output<br/>display.terminal"]
end
subgraph Display["Display Backends"]
TD[TerminalDisplay]
PD[PygameDisplay]
SD[SixelDisplay]
KD[KittyDisplay]
WSD[WebSocketDisplay]
ND[NullDisplay]
end
SourceStage --> RenderStage
RenderStage --> EffectStages
EffectStages --> DisplayStage
subgraph Async["Async Sources"]
NTFY[NtfyPoller]
MIC[MicMonitor]
end
SourceStage --> SourceCaps
RenderStage --> RenderCaps
EffectStages --> EffectCaps
DisplayStage --> DisplayCaps
subgraph Animation["Animation System"]
AC[AnimationController]
PR[Preset]
end
Sources --> Fetch
RSS --> FC
PoetryFeed --> FP
FC --> Cache
FP --> Cache
Cache --> MB
Strip --> MB
Trans --> MB
MB --> SC
NTFY --> SC
SC --> RTZ
CAM --> RTZ
Grad --> RTZ
VT --> RTZ
RTZ --> EC
EC --> ER
ER --> EffectsPlugins
EffectsPlugins --> BW
BW --> RL
RL --> Display
Ntfy --> RL
Mic --> RL
MIC --> RL
style Sources fill:#f9f,stroke:#333
style Fetch fill:#bbf,stroke:#333
style Prepare fill:#bff,stroke:#333
style Scroll fill:#bfb,stroke:#333
style Effects fill:#fbf,stroke:#333
style Render fill:#ffb,stroke:#333
style Display fill:#bbf,stroke:#333
style Async fill:#fbb,stroke:#333
style Animation fill:#bfb,stroke:#333
style SourceStage fill:#f9f,stroke:#333
style RenderStage fill:#bbf,stroke:#333
style EffectStages fill:#fbf,stroke:#333
style DisplayStage fill:#bfb,stroke:#333
```
## Stage Adapters
Existing components are wrapped as Stages via adapters:
### Source Stage Adapter
- Wraps `HeadlinesDataSource`, `PoetryDataSource`, etc.
- Provides `source.*` capabilities
- Fetches data and outputs to pipeline buffer
### Render Stage Adapter
- Wraps `StreamController`, `Camera`, `render_ticker_zone`
- Provides `render.output` capability
- Processes content and renders to canvas
### Effect Stage Adapter
- Wraps `EffectChain` and individual effect plugins
- Provides `effect.*` capabilities
- Applies visual effects to rendered content
### Display Stage Adapter
- Wraps `TerminalDisplay`, `PygameDisplay`, etc.
- Provides `display.*` capabilities
- Outputs final buffer to display backend
## Pipeline Mutation API
The Pipeline supports dynamic mutation during runtime:
### Core Methods
- `add_stage(name, stage, initialize=True)` - Add a stage
- `remove_stage(name, cleanup=True)` - Remove a stage and rebuild execution order
- `replace_stage(name, new_stage, preserve_state=True)` - Replace a stage
- `swap_stages(name1, name2)` - Swap two stages
- `move_stage(name, after=None, before=None)` - Move a stage in execution order
- `enable_stage(name)` / `disable_stage(name)` - Enable/disable stages
### Safety Checks
- `can_hot_swap(name)` - Check if a stage can be safely hot-swapped
- `cleanup_stage(name)` - Clean up specific stage without removing it
### WebSocket Commands
The mutation API is accessible via WebSocket for remote control:
```json
{"action": "remove_stage", "stage": "stage_name"}
{"action": "swap_stages", "stage1": "name1", "stage2": "name2"}
{"action": "enable_stage", "stage": "stage_name"}
{"action": "cleanup_stage", "stage": "stage_name"}
```
## Camera Modes
The Camera supports the following modes:
- **FEED**: Single item view (static or rapid cycling)
- **SCROLL**: Smooth vertical scrolling (movie credits style)
- **HORIZONTAL**: Left/right movement
- **OMNI**: Combination of vertical and horizontal
- **FLOATING**: Sinusoidal/bobbing motion
- **BOUNCE**: DVD-style bouncing off edges
- **RADIAL**: Polar coordinate scanning (radar sweep)
Note: Camera state is provided by `CameraClockStage` (capability: `camera.state`) which updates independently of data flow. The `CameraStage` applies viewport transformations (capability: `camera`).
## Animation & Presets
```mermaid
@@ -161,7 +185,7 @@ flowchart LR
Triggers --> Events
```
## Camera Modes
## Camera Modes State Diagram
```mermaid
stateDiagram-v2