delivery-kid: port Coconut V2 finalize (httpstream) + disable broken fast path#94
Merged
jMyles merged 1 commit intoJun 1, 2026
Conversation
…fast path Three related fixes for the regression that produced empty Release pages (the Nine Pound Hammer case: Release CID points at an IPFS dir containing only metadata.json, no playable content). ## 1. submit_to_coconut: V2 httpstream for finalize Replace cryptograss#90's NotImplementedError. Verified against api.coconut.co/v2/jobs that the minimal V2 shape returns HTTP 201: { "input": {"url": "..."}, "storage": {"service": "coconut"}, "outputs": {"httpstream": {"hls": {"path": "/hls"}}}, "notification": {"type": "http", "url": "..."} } Quality variants / trim / codec customization aren't yet exposed because the V2 schema for those inside httpstream isn't documented and we get 201 on the minimal shape. Falls back to Coconut V2 defaults for now; warning logged when callers pass qualities/trim that won't land. Follow-up to expose those. ## 2. Disable the finalize fast path The fast path at finalize_sse_generator was reusing state.preview_cid as the Release CID when wants_transcode + preview_cid + no trim. Safe pre-V2 (preview produced full HLS), broken post-V2 (preview produces a single mp4 — different artifact than finalize). Worse: when the V2 webhook download wasn't ported yet, preview_cid pointed at an IPFS dir containing only metadata.json, and finalize blindly reused that. That's the chain that produced the empty Release page. Always go through the finalize transcode path until preview_cid can be trusted to point at finalize-grade HLS. ## 3. download_hls_outputs: handle V2 callback shape Coconut V2's webhook callback returns ``outputs`` as a list of dicts (``[{"key": "httpstream", "url": ..., ...}]``), not the V1 dict shape (``{"hls_av1_720p": {"url": ...}}``). Normalise both into a uniform list, recognise the httpstream key, and chase the master playlist → variant playlists → segments. Drops V1 keys silently. Added _download_hls_variants_from_master that parses EXT-X-STREAM-INF entries from the master playlist and fetches each variant + segments. ## Why this is the right scope right now This is the minimum to get finalize producing real Release pages with real HLS content again, in time for tour shows. The variant/codec/trim customization is a clear follow-up but doesn't block uploads working.
6 tasks
jMyles
added a commit
that referenced
this pull request
Jun 1, 2026
The Coconut webhook handler was only updating the *job* state — not the draft state — when a finalize-side job completed. Net effect: - HLS got transcoded and pinned to IPFS ✓ - job.hlsCid was set ✓ - But draft.json never got `status: finalized` or `final_cid` written - Wiki diagnostics panel stayed stuck on "finalizing" forever - Blue Railroad Imports bot never saw a finalized draft, so no Release page got created Verified end-to-end against terrapin re-finalize (PR #94 deploy): Coconut V2 ran cleanly, HLS pinned at QmVUq..., but the wiki page showed nothing past "transcoding-submitted" and no Release appeared. Two fixes: ## 1. content.py finalize path adds draftId to job_state The preview-path job_state already had draftId so the webhook handler could map back to a draft. The finalize-path job_state was missing it — so even with the new _update_draft_finalize below, the webhook wouldn't know which draft to update. ## 2. coconut.py adds _update_draft_finalize + wires it in Mirror of _update_draft_preview for the finalize side. On job.completed: state.status = "finalized", state.final_cid = hlsCid, finalize_log appended, wiki snapshot fired. On job.failed: state.status = "finalize_failed", error logged. Webhook handler's tail now branches on isPreview to call the right updater rather than only handling preview jobs. This is a pre-existing gap exposed by PR #94 — pre-V2, the finalize fast path was reusing preview_cid and the slow Coconut-finalize path was rarely hit, so the missing draft-state update went unnoticed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TL;DR
Closes the chain that produced empty Release pages (the Nine Pound Hammer regression):
V2 schema discovery (continued from #90)
Curl-discovered the same iterative way as the `mp4` shape:
```bash
KEY=$(docker exec pinning-service printenv COCONUT_API_KEY)
J='{"input":{"url":"..."},'
J+='"storage":{"service":"coconut"},'
J+='"outputs":{"httpstream":{"hls":{"path":"/hls"}}},'
J+='"notification":{"type":"http","url":"..."}}'
echo "$J" | curl -s -w "\nHTTP %{http_code}\n" -u "$KEY:" -H "Content-Type: application/json" \
-X POST https://api.coconut.co/v2/jobs --data-binary @-
```
Result: `HTTP 201` with `outputs:[{key:httpstream, type:httpstream, format:httpstream, status:httpstream.waiting}]`. Confirms the minimum-viable shape works.
What this doesn't port yet
Test plan
Known unknowns
The V2 webhook callback payload — specifically the post-completion shape with `url` populated — isn't directly verified yet (Coconut hasn't called us back successfully under V2 for a real upload). The normalization is defensive but the FIRST real callback under this PR will tell us if anything else needs adjusting. Build-watch-iterate; should be a fast loop.