Skip to content

Integrity check is observable on the wire and survives reload #495

Description

@JArmandoAnaya

The weights integrity check still holds a client-side job id: a reload loses a
check in flight. That is the failure mode #492 eliminated for the download, still
present on the other action over the same files. Recorded under "found, not fixed"
in #494; this issue gives it the home the process requires.

cf. #475, #486, #492, #493, #494.

Observed

  1. Open a ready local connection's overflow and press Check files are undamaged.
  2. The row reads Reading every file… with an n of m files microline.
  3. Reload, or open the screen in a second tab. The row reads Ready with the same
    menu item offered again, as though nothing were happening. The check is still
    reading gigabytes in the worker; nothing on screen says so.

The same is true of a check somebody started from the CLI or from MCP: the
browser has no way to know one is running, because the only thing that ever knew
was the tab that received the 202.

Verified before designing anything

How #493 hung the download off the connection

ConnectionOut.download carries the connection's most recent weight download —
job_id, state, bytes_done, bytes_total, error. It is derived, never
stored: InferenceConnectionService.downloads() reads
JobQueue.list(types={WEIGHT_DOWNLOAD_JOB_TYPE}), which answers newest-first, and
takes the first job per connection id. The job type and the payload key live in
kernel/domain/inference.py because the kernel may not import visionset.jobs
and both sides need one spelling. WeightDownload.of is the single place that
says a job row's processed/total mean bytes for that type.

How #494's frontend polls it

useConnections takes a refetchInterval that is a function of the answer: two
seconds while any row satisfies isDownloading, false otherwise, and false
before the first fetch lands. useDownloadRun holds no job id — it reads
connection.download. Recovery across a reload is then a property of the shape.

How the check reaches the client today — the path being retired

useIntegrityRun (InferenceScreen.tsx) keeps useState<string | null> for a
job id, set from the mutation's onSuccess, and polls useBackgroundJob(jobId).
So only the mount that pressed the item can observe the run. This is the exact
construction #493/#494 removed from the download.

What the check job already reports

check_integrity owns its loop and knows its total before the first file:
on_file(done, len(published)), which jobs/integrity.py already turns into
reporter.report(processed=checked, total=total). The job row therefore already
carries determinate file progress
— the wire is the only thing missing. No new
accounting is needed, and the issue's prose-only fallback is not required: a check
gets a real bar, counting files, named as files at the one boundary that knows the
job type.

Shape

A question this pins rather than answers

allowed_actions is not job-aware today, and this issue does not make it so.
CONNECTION_GATES is a pure function of setup state × connection type, so a
connection with a check in flight is still ready and still declares
check_integrity — and still declares download_weights, which is legal in both
states. Nothing in the kernel refuses a second concurrent check or a download
overlapping one.

That is defensible as it stands: the check job is registered idempotent, a second
run reads the same files and reaches the same verdict, and require_checkable
passes at ready precisely so a re-queued orphan and a person asking twice take
the same path. It is also wasteful — two passes over gigabytes — and the
overlap of a download and a check over one cache is a question nobody has
answered.

Making the declaration job-aware would give connection_actions a third
dimension and change what CONNECTION_GATES is. That is a design decision, not a
consequence of putting a check on the wire, so this issue pins today's answer in
a contract test and changes nothing
. The screen still disables the control while
its own check runs, which is rendering state and not computing legality.

If a concurrent check or a download-during-check should be refused, that is a
separate issue and Armando's call.

Metadata

Metadata

Assignees

No one assigned

    Labels

    apivisionset.server — REST API and OpenAPI contractbackendvisionset Python distribution — kernel, server, cli, mcp, formatsenhancementNew feature or requestfrontendannotator / ui-core / app packagesuxUser experience / interaction design

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions