Skip to content
C.W.K.
Lesson 06 of 06 · published

A Cover Is Proven by Its Pixels

~15 min · verification, readback, delivery, evolution

Level 0Cold Workshop
0 XP0/58 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete

A Cover That Was Set

On 2026-10-14, at the station in Córdoba, the owner looked at his channel and said: “근데 어제도 오늘도 썸네일을 안 만드네? 어제는 노을 사진이라 그러려니 했는데 실수로 빼먹는 거 같은데?” (“You didn't make a thumbnail yesterday or today either? Yesterday's was a sunset photo, so I let it go, but it looks like you're leaving it out by mistake”). The two newest films were wearing photographs. The records said their covers had been delivered: both uploads had sent a thumbnail, and the platform had answered that it was set. What had been sent was an unlettered source photograph, accepted as a cover because an instruction to use photos for the movie's imagery had been stretched over the cover too.

So “the thumbnail is set” had been true twice and had meant nothing twice. It proved that a request returned. It did not prove that the image was a cover, and it did not prove what viewers were shown.

What a Cover Has to Be Before It Is Sent

The first half of the fix (2026-10-15) is a definition, written for Mobile uploads and, as a later section tells, extended to every translated upload. Each such cover is generated through the family's shared image route, lettered by the generator itself, and recorded with its provenance: the route, the image and history ids, the provider and the prompt. It is reviewed in its own language at full size and at the 246-pixel feed size, the size at which a cover actually competes, and the review names the exact lettering it read. The acceptance is bound to the source file's hash. A raw photograph fails this by construction, because it has no generation provenance, and the upload stage refuses before any request when the cover is missing or unreviewed. The default lettering is English; a master lettered in another language needs the owner's recorded authorization, his words and where he said them. An ordinary Talk master stays outside the rule: when its plan names no cover it goes up without one, and a cover it does name is checked only as an accepted board, with no language review and no readback.

What Proves It Arrived

The second half is a readback, and it lives where the channel's credentials live. A loopback route in the brain's repository sets the cover when asked, then reads the video through the platform's own API, takes the largest thumbnail rendition it lists, fetches those pixels from the CDN and compares them with the file that was reviewed. It compares pixels, not addresses and not bytes. The CDN address of a video's thumbnail stays the same when the image behind it changes, so a stable URL proves nothing, and the fetch carries a cache-busting parameter so that an old response at the unchanged address cannot pass for the new image. The served image is recompressed, and the high rendition may letterbox a widescreen cover to 4:3, so byte hashes could never match either. Both images are fitted to the same small frame and compared by their mean colour difference, which must be 8.0 or less. A miss is retried a few times for propagation, and never by uploading anything again.

The receipt, out/thumbnail/delivery.json, records the source's hash, the uploaded image's hash, the served image's hash, its URL and when it was verified. It is checked again at the end: verify and land recompute it against the current cover and the current upload record, so a receipt for another video, another cover or an older export fails, and no hand-logged stage or forced landing gets past it.

The Gate That Closed Only the Master

The same evening, on the train to Seville, the owner sent a second screenshot: “어제 노을 썸네일은 피파 영중일 버전도 빼먹고 노을 사진 그대로 썼어” (“For yesterday's sunset film, Pippa's English, Chinese and Japanese versions left it out too and used the sunset photo as it was”). The new gate had been written for mobile uploads, and it looked for each language's upload record inside mobile productions. But the mobile pipeline refuses every language except Korean. Its translations run in the translation pipeline, which only asked for an accepted assets record, and whose template said to reuse the master's cover unchanged when there was no lettering to translate. So three dubs had gone up on the raw sunset photo, and a gate declared closed that same evening had never stood where they were made.

The repair, within the hour, made one cover rule for the master and every dub. Each uploaded language owns a cover generated and reviewed in that language, and a receipt of its own under out/thumbnail/<language>/, bound to that language's upload record. An English dub may share an English master cover; no language borrows a cover lettered for another; the master's verification never stands in for a dub; and finishing any pipeline requires every uploaded language's receipt. The same session downloaded the live covers of all 48 translations from the week before and of 18 Korean masters, found photo covers on exactly two dub sets, and replaced all six. The audit's receipt also keeps what it left alone. The Korean master of one of those sets, on the owner's channel, still wore its photo, because a cover on his channel changes only on his word; he gave it from Seville, and that master took its generated cover the same night. And two earlier translations carry generated covers lettered in English on their Japanese and Chinese versions. The rule written that night would refuse such a cover on a new upload, but these are not raw photos, so they were left as they are.

The lesson is not about thumbnails. A gate is a claim about where the thing it guards lives. This one guarded the place the work was expected to be, not the place it was, and one question would have caught it before the owner did: run the gate over every upload the channel actually holds.

A Refusal Is a Fact, Too

The platform limits how many custom thumbnails a channel may set in a day. On the evening of 2026-10-14 the Japanese cover of the Córdoba dub was refused with HTTP 429 uploadRateLimitExceeded, and the readback found the served image still differing from the reviewed one by 91.069. Two productions handled that with hourly retry scripts written by hand; in Córdoba's case the third attempt verified. The workshop then made it one command, pipeline.py cover --slug … [--language L] [--every 3600]. One runner per upload holds a lock, and a second exits without trying. Each attempt reads back first and sets the cover only when the readback fails, so a set that already took is never spent again on a limited channel. The upload's identity is rechecked on every attempt, every attempt is appended to retry.json, and a missing or unreviewed cover stops it at once, because no amount of waiting fixes that.

Movies get the same treatment. Before an upload request goes out, out/upload-pending.json records the movie's hash, the title and the channel, so a run that dies before the answer is written can only send the same movie under the same title again, which the door recognizes as the same upload; a different movie or title over it is refused. A refusal because the day's uploads are spent goes to out/upload-blocked.json with the hour the platform's upload day starts again. Neither is a failure to hide. Each is a state with a receipt (lesson 5 of this track).

Unlisted Is Its Own Fact

Every upload still goes up private. During the trip the owner began asking for editions to be unlisted on Pippa's channel, watchable by link before anything is public, and that switch is a fact of its own, made only on his named word. The engine reads the video first and refuses one that is already public or carries a publication schedule. It changes only the privacy status and carries the other status fields over, because the platform's update replaces the whole status block and a field left out would be reset. Then it reads the video back and writes a receipt holding his authorization, the before and the after. Nothing in that path can make a video public.

A write that succeeded is a claim; the served result is the fact. When the thing you deliver is shown by someone else's system, read back what that system serves and compare it with what you reviewed, in the form a viewer receives. Give each delivery its own receipt, run every gate over where the work actually lives, and turn every refusal into a recorded state that can only ever repeat the same request.

Code

verbatim, cwkPippa backend/services/youtube_upload.py, as of 2026-10-27·python
def _thumbnail_difference(expected: bytes, actual: bytes) -> float:
    """Compare recompressed CDN pixels, not stable URLs or JPEG byte hashes."""
    from PIL import Image, ImageChops, ImageOps, ImageStat
    with Image.open(io.BytesIO(expected)) as left, Image.open(io.BytesIO(actual)) as right:
        # YouTube's high rendition may letterbox a widescreen cover to 4:3.
        size = (96, 54)
        a = ImageOps.fit(left.convert("RGB"), size, method=Image.Resampling.LANCZOS)
        b = ImageOps.fit(right.convert("RGB"), size, method=Image.Resampling.LANCZOS)
        return sum(ImageStat.Stat(ImageChops.difference(a, b)).mean) / 3
verbatim, beacon/thumbnail.py, as of 2026-10-27·python
def verify_delivery(ep: Path, language: str | None = None) -> dict:
    """Completion requires a readback bound to this cover and this upload."""
    source, _ = cover_source(ep, language)
    folder = cover_folder(ep, language)
    upload = _upload_record(ep, language)
    receipt_path = folder / "delivery.json"
    receipt = json.loads(receipt_path.read_text()) if receipt_path.exists() else {}
    remote = receipt.get("verification") or {}
    export = folder / "thumbnail-youtube.jpg"
    if (receipt.get("source_sha256") != storage.sha256(source)
            or remote.get("schema") != "pippa.youtube-thumbnail.v1"
            or remote.get("thumbnail") != "verified"
            or remote.get("id") != upload.get("id")
            or remote.get("channel") != upload.get("channel")
            or not remote.get("verified_at") or not remote.get("served_sha256")
            or not remote.get("url") or not export.is_file()
            or remote.get("image_sha256") != storage.sha256(export)):
        raise ValueError(f"{language or 'master'} custom thumbnail delivery is missing or stale; "
                         "verify the current cover on the existing video")
    return receipt
One upload's delivery facts and their receipts (sketch)·text
fact                              receipt                                   written by
--------------------------------  ----------------------------------------  ------------------
cover is a reviewed cover         assets record: ember provenance, prompt,  the producer
                                  thumbnail_review {language, lettering,
                                  full_size, feed_size}, source sha256
request sent, answer unknown      out/upload[-L]-pending.json               upload, BEFORE send
day's uploads spent               out/upload[-L]-blocked.json + reset hour  upload, on refusal
movie uploaded, private           out/upload[-L].json                       upload, from the door
cover served by the platform      out/thumbnail[/L]/delivery.json           the brain's readback
cover refused for quota           out/thumbnail[/L]/retry.json              cover --every 3600
unlisted on his word              out/unlisted-delivery[-L].json            the brain's switch

# verify and land recompute delivery.json against the CURRENT cover
# and the CURRENT upload record; a stable CDN URL is never evidence.

External links

Exercise

Pick something you deliver into a system you do not control: an image to a CDN, a record to a partner's API, an email through a provider, a configuration pushed to devices. Write down what your process treats as proof of delivery today. Then design the readback: what you would fetch from the other system, in the form an end user receives it, how you would compare it with what you reviewed when the other system transforms it, which refusals you would record as states rather than errors, and what guarantees a retry can only repeat the same request.
Hint
The tell is a success flag that comes from your own request rather than from the other side's output. Then check the addresses: if the location of the delivered thing stays the same when its content changes, reading the location proves nothing, and caches will happily serve you the old content while everything looks green.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign in — Please sign in to comment.

No comments yet — be the first.