Space Channel Content Refresh Design
Date: 2026-06-29
Goal
Make the Space Channel phone number useful without depending on live page scraping or live Gemini speech for known content during a call.
The production phone path should:
- answer with static droid audio for known prompts;
- fetch read-only Space Channel data before speaking dynamic content;
- put the dynamic content into slots;
- speak the entire dynamic line through
droid_full_buffer; - pace outbound Telnyx media in 20 ms chunks using the fixed absolute-deadline sender.
Current Implementation
Refresh command:
.venv/bin/python scripts/space_channel_refresh.py --once
Long-running four-hour refresh loop:
.venv/bin/python scripts/space_channel_refresh.py --daemon --interval-hours 4
Cron-style four-hour schedule:
0 */4 * * * cd /Users/davidmar/src/riff && .venv/bin/python scripts/space_channel_refresh.py --once >> logs/space_channel_refresh.log 2>&1
Runtime cache:
data/space_channel/content_snapshot.json
That cache is generated runtime data and is ignored by git. If it is missing or
expired, space_content_fetch attempts one refresh during the read-only act
state before it speaks.
Data Sources
V1 uses two Space Channel-facing sources:
- Launch Command:
https://www.spacechannel.com/data/launches.json, with Launch Library fallback already inspace_launches_fetch. - Dashboard catalog:
https://www.spacechannel.com/, parsed for the current Space Channel widget list and subtitles.
The homepage currently exposes widgets such as Launch Command, Daily Briefing, Cosmic Weather, Anomaly Division, Intelligence Feed, ISS Operations, Music, and Solar Operations. The phone briefing uses that catalog so callers can ask what is online, ask about Space Channel news, solar weather, UFO/UAP files, or radio status, and receive a real current dashboard briefing instead of a generic "queued" message.
Phone Flow
Production route:
+15122777311 -> space_channel_network_ops
Important states:
greeting: static droid WAV.suggestions_announce: static droid WAV, regenerated after the capability text changed.fetch_launches: callsspace_launches_fetch, then entersreport_launches_audio.report_launches_audio:droid_full_bufferslot-templated launch summary.fetch_space_content: callsspace_content_fetch, then entersreport_space_content_audio.report_space_content_audio:droid_full_bufferslot-templated dashboard or topic summary.bug_captured_audio:droid_full_bufferacknowledgement of captured bug text.
Terminal states keep entry.line for text-mode transcripts and evals. The
phone path records and speaks the preceding play_audio.text, then transitions
to the terminal and hangs up at a logical completion point.
Audio Learning Applied
The diagnostic calls showed that prerecorded audio was not sufficient by itself. The phone path became clear only when outbound Telnyx media was sent as:
- 20 ms chunks;
- pre-encoded mu-law/base64 frames;
- absolute-deadline paced sends;
- no synthesis work inside the paced send loop.
For Space Channel V1, static prompts are still pre-rendered, but dynamic content uses full-buffer droid synthesis plus the same paced sender. This avoids the sentence-by-sentence choppiness that appeared when generation and sending were too tightly coupled.
Latency Learning
The 2026-06-29 phone export showed a separate problem from audio quality. After
the caller asked for UFO files, user_transcription and update_slots landed
within milliseconds, but the phone did not start the RIFF-owned content audio
until about 11.9 seconds later. The intervening audio was Gemini Live output
that the phone path suppressed because Space Channel owns those states.
The applied mitigation has three layers:
- The classifier prompts now explicitly say nothing after
update_slots; RIFF will play the next phone-safe audio state. - Space Channel opts into a bounded
phone_processing_tone, a short droid compute chirp that starts after a 700 ms wait and loops until real agent audio starts or the max wait expires. - Static audio transitions into blank terminal states no longer send a Live policy-change prompt, so Gemini does not improvise an extra goodbye after the authored Space Channel line has completed.
The deeper follow-up is to fast-forward RIFF-owned act and static chains
immediately after a deterministic tool result instead of waiting for Gemini's
suppressed turn to complete. That would remove the wait; the processing tone is
the caller-facing fallback while that broader handoff is designed.
Next Data Connectors
The V1 cache provides current dashboard presence/status and launch data. The next connectors should deepen the summaries without changing the phone flow:
- Daily Briefing article ingestion.
- NOAA/SWPC solar weather values for the solar weather path.
- UFO/UAP document headline ingestion for the intelligence path.
- Radio/now-playing metadata or live stream handoff.
Those can all write into the same topics object in
content_snapshot.json; the phone flow only needs space_content_summary.
Verification
Focused test command:
.venv/bin/python -m pytest \
tests/test_space_channel_content.py \
tests/test_space_channel_tools.py \
tests/test_space_channel_flow.py
Live refresh smoke test:
.venv/bin/python scripts/space_channel_refresh.py --once --json
Static menu audio regeneration:
.venv/bin/python -m riff.static_audio generate \
--flow space_channel_network_ops \
--state suggestions_announce \
--force