-- One row per rendered episode. -- -- The MP3 lives in blob storage; this is the index the feed reads. Without it -- there is no way to answer "has this mission already been rendered?", and a -- sweep that re-renders on every tick would spend real money each time — the -- same lesson `corpus_items` taught for papers: a recurring job's hard problem -- is knowing what it already did. CREATE TABLE IF NOT EXISTS podcast_episodes ( id UUID PRIMARY KEY, workspace_id UUID NOT NULL REFERENCES workspaces (id) ON DELETE CASCADE, -- The mission whose script this came from. One episode per mission: a -- mission is one day's research, and re-running it should replace the -- episode rather than add a second one for the same material. mission_id UUID NOT NULL REFERENCES missions (id) ON DELETE CASCADE, UNIQUE (mission_id), -- Vault date folder the script came from, e.g. 2026-08-18. Not derived from -- created_at: a mission that runs past midnight belongs to the day it -- harvested, not the day it finished rendering. episode_date TEXT NOT NULL, title TEXT NOT NULL, -- Blob key for the MP3. blob_key TEXT NOT NULL, bytes BIGINT NOT NULL, duration_secs INTEGER NOT NULL, -- Which backend voiced it, for attribution when a future one sounds different. rendered_by TEXT NOT NULL, -- Hash of the script that produced this audio. A phase that re-runs and -- rewrites its script must produce a NEW episode; an unchanged script must -- not be re-rendered and re-billed. script_sha TEXT NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX IF NOT EXISTS podcast_episodes_feed_idx ON podcast_episodes (workspace_id, created_at DESC); COMMENT ON TABLE podcast_episodes IS 'Rendered podcast episodes. The audio is in blob storage; this indexes it for the RSS feed and prevents re-rendering (and re-billing) work already done.';