Follow-up from the review of #1392 (raised by @cosarah).
Problem. The "store bytes in the pool → clear the store-full marker → write the reference back → mirror locally" sequence now exists in three places with three refusal semantics:
- the media pass (
lib/media/media-orchestrator.ts): a refusal for room keeps the synthesized bytes locally so a later Retry re-uploads them without paying the provider again;
- narration adoption (
lib/audio/adopt-cached-narration.ts): a refusal skips the clip and it is attempted again on a later load;
- fresh TTS synthesis (
lib/hooks/use-scene-generator.ts): a refusal for room discards the freshly synthesized, already-billed audio before the local cache write, so every retry re-calls the TTS provider.
The third one is the concrete defect: it is exactly the double billing the media pass's retained-bytes contract exists to prevent. Fixing it in place would add a fourth variant.
Proposal. Extract one client-side pool commit primitive (commitToPool({ stageId, bytes, mimeType, slot, ... })) that owns the sequence and the refusal semantics (retain bytes locally under the placeholder/derived key on a room refusal; clear the marker on success at the seam; write back through mutateDocument; mirror locally), and make the three callers use it. The TTS path then gets retained-bytes semantics for free.
Scope note. This is a refactor across three modules and belongs in its own PR so #1392 stays reviewable.
Follow-up from the review of #1392 (raised by @cosarah).
Problem. The "store bytes in the pool → clear the store-full marker → write the reference back → mirror locally" sequence now exists in three places with three refusal semantics:
lib/media/media-orchestrator.ts): a refusal for room keeps the synthesized bytes locally so a later Retry re-uploads them without paying the provider again;lib/audio/adopt-cached-narration.ts): a refusal skips the clip and it is attempted again on a later load;lib/hooks/use-scene-generator.ts): a refusal for room discards the freshly synthesized, already-billed audio before the local cache write, so every retry re-calls the TTS provider.The third one is the concrete defect: it is exactly the double billing the media pass's retained-bytes contract exists to prevent. Fixing it in place would add a fourth variant.
Proposal. Extract one client-side pool commit primitive (
commitToPool({ stageId, bytes, mimeType, slot, ... })) that owns the sequence and the refusal semantics (retain bytes locally under the placeholder/derived key on a room refusal; clear the marker on success at the seam; write back throughmutateDocument; mirror locally), and make the three callers use it. The TTS path then gets retained-bytes semantics for free.Scope note. This is a refactor across three modules and belongs in its own PR so #1392 stays reviewable.