Skip to content

Pre-labeling runs once per asset, and re-uploading the same media is not a reset #683

Description

@JArmandoAnaya

Batch pre-labeling runs once over a given piece of media and can never run over it again. The
recovery a person naturally reaches for — upload the footage again, or cut a new batch — does not
work, and nothing says why.

Three rules combine to produce it, and each is right on its own:

  • An asset is its bytes. content_hash is the SHA-256 of the file and the same bytes ingested
    twice are one asset over one blob, under uq_asset_project_content_hash. Re-uploading resolves
    to the asset that already exists.
  • Annotations hang off an asset_id and nothing else, so they follow the asset into every
    batch cut over it. initial_progress opens such an asset at annotated deliberately, because
    filing it under "nothing labeled here" while the editor draws three boxes is a lie a gallery
    filter repeats.
  • A pre-labeling run writes only where nothing has been written, which is what stops it
    overwriting a person's work and what makes a re-run after a crash safe.

So a second pass finds no eligible asset. A new batch over the same footage opens with every frame
already carrying the first run's labels, and the pre-label control correctly reports there is
nothing to touch. Observed directly: a fresh batch over a previously pre-labelled video showed
"Unannotated (0)" with the earlier round's boxes on every thumbnail.

That matters because the first pass is rarely the one you keep. A zero-shot detector at a threshold
you are still tuning is exactly the thing you want to run again — at a lower floor, or against a
schema you have since corrected — and the current design offers no way to do it short of deleting
every annotation on every frame by hand.

What has to be decided. A re-run needs a rule for labels that already exist, and the shape that
looks right is: replace provenance: model annotations, leave provenance: human ones untouched.
That keeps the protection the write rule was built for — a person's work is never destroyed — while
letting the machine's own output be superseded by a better run. It is a different write path from
the one that shipped, and it needs its own atomicity story: a replacing run must not leave a frame
holding half of two rounds.

Worth settling alongside it:

  • Whether a re-run is offered per batch or per selection, since a reviewer may want to redo the
    frames they rejected rather than all of them.
  • What the surface says before it starts, given it is destructive to machine labels in a way the
    first run never was.
  • Whether the count of what was replaced belongs in the job's result, beside the regions a run
    discards today.

The spine shipped in #673, and the decision that gave a model's labels their own progress state is
recorded on #425. Neither answers this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    backendvisionset Python distribution — kernel, server, cli, mcp, formatsenhancementNew feature or requestkernelvisionset.kernel — domain, ports, adapters, services

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions