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

A Correction Is a Successor

~14 min · immutability, revisions, delivery, evolution

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

The Sentence That Could Never Have Been True

Until this version, track 3's lesson on the channel said that a change the owner asks for after an upload is a new render that replaces the upload. It reads like an ordinary production promise, and it describes something the platform does not offer: there is no way to swap the movie under an existing video's address. A new movie is a new video, with its own address, its own receipts and its own history. So the real question was never how to replace an upload. It was what to do with the old one, and with everything the workshop had recorded about it, once a better one goes up.

Two corrections on the Spain trip forced the answer inside two days. On 2026-10-21 the cut of the Frigiliana day let the voice read the owner's “one of us”, written in Hangul, as “one of earth”. The corrected cut went up as a new private video, and the first stayed private as revision 1. On 2026-10-22 the Nerja day placed phone photos of two restaurants he had also photographed with his own camera, and he said so plainly: “최고의 맛집들이라고 하고 아이폰 사진 쓰는 게 미안하다” (“Calling them the best places to eat and then using iPhone photos, that's a shame”). The camera cut went up as a new private video with the same approved script and the same voices. Both sessions built a revisions/r01/ folder by hand and renamed the old upload record to out/upload-r01.json. Nothing recorded which video replaced which, and the guard that stopped a second upload was, in the code's own later words, a filename.

An Upload Is Immutable

Review 5 (2026-10-22, 63bc75e) turned the habit into a mechanism, and it started from a refusal. Every check that asks whether a production is uploaded now reads one function, which lists only the current upload records, and two stages refuse on its answer. video will not render while a current upload exists: “uploaded movies are immutable … a corrected cut is a revision”. upload will not send a different movie over an existing record, and run again on the same movie it never sends a second copy; where the cover is gated, it repairs and reads back only that video's cover. The record of what went up cannot be overwritten by accident, because nothing will write over it.

The Revision Moves the Evidence Aside

A correction is a command that needs the owner: pipeline.py revise --slug … --note … --said … --source-ref …. Without his actual words and where he said them it refuses, because a revision is his request, never a request to keep working. It then moves the whole receipt set of the superseded upload into the next free revisions/rNN/, under the same relative paths: the upload record and its page, the cover's delivery receipt, retry log and exports, the movie's validation, quality, QA and glyph readback records, the watch notes, the authored manifest, and the uploaded movie file whose bytes the record names, so that video can render the corrected cut in its place. What it never moves is the production's ground: the edit, the presentation layer, the frozen intake and material, the audio, the picture, the accepted cover pictures and every audit history.

The care is in the order. The record, superseded.json with complete: false, is written before the first move, and the upload records move last, so the production keeps reading as uploaded until the whole set is aside; a run that stops part way is finished by the next call, in the same folder. Files move by a rename on one volume, never by a copy followed by a delete, and across volumes the command refuses rather than risk a half-moved set. A target that already exists is never overwritten. A cover retry still running on one of those uploads blocks the revision until it ends.

When the corrected cut goes up, the upload stage stamps it on the revision as the successor, one per language. A successor already named is never overwritten, and naming the superseded video as its own successor is refused. The delivery projection then marks every superseded row with its revision and its successor. The two folders built by hand on October 21 and 22 are still read, their successors inferred from the next upload in the same language.

The Old Video Stays, and a Deletion Is Observed

The superseded video stays on the platform exactly as it was. At first that was not a choice. The owner published the Nerja camera cut, deleted the superseded one himself, and said why it had to be him: “피파는 삭제 권한 없어서 어차피 못 지우더라고. 삭제는 아빠가 해야해” (“Pippa has no permission to delete, so she couldn't anyway. Deleting is mine to do”). Pippa's upload account can upload, set privacy and set covers; it cannot delete.

Baseline 1.9 of the procedure (2026-10-22, c4ab71b) made that a rule about records as much as about rights. When a revision supersedes an upload, Pippa leaves the old video alone, tells him which video is his to delete, and reports it as pending on him; revise prints exactly that. A deletion is recorded only from evidence, his own words or beacon delivery --reconcile observing the video gone, never because a deletion was asked for, and never in a sentence where Pippa removed something. The Nerja record has that shape: the reconcile observed the old video as deleted, and no record says Pippa took it down.

Why the History Has to Survive

Lesson 5 of this track argued that once a person approves a result, regeneration stops being reproduction, and the approved film has to be sealed. A correction is the same argument one step later, at delivery. The superseded upload was a delivered fact: it was watched, its cover was read back, a link to it may have travelled. Overwriting its records would make the workshop's history say that the corrected cut was the only one ever made. The procedure forbids exactly that in its own words: archived movies and old approvals are never rewritten to look as if they had followed a rule introduced later. So the revision folder keeps the old upload's evidence whole, the successor stamp says what followed it, and the delivery projection says what the platform shows today. Three facts, three receipts (track 7, lesson 5).

A delivered artifact is not edited; it is succeeded. Make the delivered thing immutable in your tool, move its evidence aside under a record that names the request and who made it, stamp the replacement as its successor, and record the old one's fate only from what you observe. History a correction rewrote cannot be audited. History a correction extended can.

Code

What a revision moves, and what it leaves (sketch of beacon/revisions.py and the upload stage, as of 2026-10-27)·text
pipeline.py revise --slug <slug> --note "<what it corrects>" \
    --said "<the owner's words>" --source-ref "<where he said them>"

refuses:  no --said or --source-ref       (a revision is his request)
          no current upload record         (before any upload: just re-render)
          a cover retry still running      (let it finish)

revisions/r02/superseded.json   written FIRST, complete: false
revisions/r02/out/...           moved, same relative paths, os.rename only
  validate.json  quality.json  producer-qa.json  glyph-readback.json
  WATCH.md  authored-talk.json  (and a dub's -<lang> twins)
  thumbnail/[<lang>/]delivery.json  retry.json  derived exports
  UPLOAD[-<lang>].md
  <the uploaded movie whose bytes the record names>
  upload[-<lang>].json          moved LAST: the guard holds until here

stays:    edit.json  presentation.json  mobile/  material/  audio/
          picture/  the accepted cover pictures  every audit history

upload (corrected cut)  -> a new private video
                        -> stamp_successor: superseded_by.<lang|master>
beacon delivery         -> row.superseded = {revision, by}
the old video           -> stays; deleting it is the owner's step,
                           recorded only when observed
verbatim, beacon/revisions.py, as of 2026-10-27·python
def stamp_successor(ep: Path, language: str | None, result: dict) -> dict | None:
    """After a new upload, name it as the successor on the latest revision
    that superseded this language's video. Returns the updated record, or
    None when no revision is waiting for one (an ordinary first upload, or a
    successor already named, which is never overwritten)."""
    ep = Path(ep)
    for _, folder in reversed(_revision_dirs(ep)):
        record = _record(folder)
        if record is None or not record.get("complete"):
            continue
        listed = [video for video in record.get("videos") or [] if video.get("language") == language]
        if not listed:
            continue
        successors = record.setdefault("superseded_by", {})
        if _key(language) in successors:
            return None
        if result.get("id") in {video.get("video_id") for video in listed}:
            raise ValueError(f"{result.get('id')} is the video {record['revision']} superseded, not its successor")
        successors[_key(language)] = {"video_id": result["id"], "watch_url": result.get("watch_url"),
                                      "at": result.get("at") or storage.now()}
        storage.write_json(folder / RECORD, record)
        return record
    return None

External links

Exercise

Pick something you deliver that people may already have consumed: a released package version, a sent invoice, a published post, a deployed model. Write down what your process does today when it has to be corrected. Then design the version where the delivered thing is immutable in your tool: what the correction command must be given before it runs, what it moves aside and what it leaves in place, how the replacement names what it replaces, and which of the old thing's fates you can only observe rather than perform.
Hint
Package registries are the clean precedent: a published version cannot be overwritten, so a fix is a new version, and a yank only marks the old one. The part teams forget is the record of the request. A correction that cannot say who asked for it, and in what words, will be argued about later, and the argument will have nothing to read.

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.