Postmortem2026-08-258 min

I marked a swing, closed the app, and discovered the annotation was never a record.

Swing Trainer needed to preserve partial human review without calling incomplete work training truth. The revision model that keeps drafts, labels, and source video separate.

I marked a swing, closed the app, and discovered the annotation was never a record.

The first version of the Mac review workspace had a button called Save JSON.

It worked. That was the problem.

The file it wrote contained club evidence, but not the complete review state around it. Trim In, Trim Out, Address, Takeaway, Top, Impact, and Finish could remain only in the interface. The exported JSON looked official while omitting most of the decisions the reviewer had made.

Nothing corrupted the original movie. The system had done something more subtle: it produced a valid-looking record that was incomplete by design and failed to say so.

One button was hiding three artifacts

The review workflow actually produces three different things:

  1. A partial workspace draft that should survive interruption.
  2. A narrow club-evidence export that may be useful on its own.
  3. A complete human review containing trim boundaries, five swing phases, club-point states, and source provenance.

The first implementation treated those as variations of Save. They are not variations. They have different completeness rules and different authority.

We renamed the narrow action Export Club Evidence Only and created two separate revision contracts. A workspace draft can preserve partial work, but its training disposition remains blocked. A complete review revision requires both trim boundaries, every required phase, compatible club evidence, the source and queue snapshot, and a hash linking it to the prior revision.

Neither artifact is allowed to overwrite the one before it.

The first physical save still failed

The code change passed its tests, then the installed app exposed a second break.

The review queue was visible. The movie played. I could set Trim In and mark Address. But Save & Continue refused because the application no longer considered the open queue verified.

The screen looked like a verified review session while the provenance guard had lost one of the facts that made it verified: the queue URL, the ordered movie identities, or the retained authorization to the external data root.

We fixed that by making the verified queue a live session object rather than a temporary check. The interface now says VERIFIED REVIEW only when the queue identity, ordered files, and retained root authorization still agree. A generic file selection is labeled MOVIE LIST and cannot save or resume as reviewed corpus work.

On the physical Mac, the next build opened the exact 20-clip queue and displayed VERIFIED REVIEW 1/20. I set Trim In and Address, then tried to continue. The app stayed on clip one and named everything still missing: Trim Out, Takeaway, Top, Impact, Finish, and club evidence. It wrote no completed revision.

That refusal was the successful result.

Partial work still has to survive

Failing closed solved false completion, but it left a human problem. Real annotation work is interruptible. Someone may mark one boundary, stop for dinner, and return tomorrow. Discarding that work is honest but unusable.

The next revision added durable workspace drafts. A draft is bound to the exact source and queue identity, stored append-only, and restored only after the source timeline is decoded again. It remains explicitly blocked from training.

The physical test was deliberately incomplete. I opened a synthetic review movie, set Trim In, quit the app, relaunched it, and saw the same Trim In restored. I then attempted completion. The app refused because the rest of the evidence was absent. The workspace contained one draft revision. The movie was unchanged.

The committed work passed 126 shared tests, 14 focused Review-contract tests, and 70 Mac presentation tests before that installed-app exercise.

What a saved label means now

A saved draft means the reviewer's partial work is durable.

It does not mean the swing is reviewed. It does not mean the annotation is eligible for training. It does not mean the source movie was edited. It does not mean the five-point club evidence is complete.

We still have not physically completed, saved, reopened, and exported a full real five-point review through the training pipeline. That gate remains open.

The lesson is broader than video annotation. Persistence and completion are different promises. If a system cannot represent that difference, it will either lose honest work or promote unfinished work into truth.

I would rather have a durable draft that says “not done” than a polished JSON file that lies about what it contains.