Skip to content

fix(validation) report status of checked segments, not just completed#661

Merged
javi11 merged 1 commit into
javi11:mainfrom
evulhotdog:fix/segment-validation-reporting
Jun 4, 2026
Merged

fix(validation) report status of checked segments, not just completed#661
javi11 merged 1 commit into
javi11:mainfrom
evulhotdog:fix/segment-validation-reporting

Conversation

@evulhotdog

Copy link
Copy Markdown
Contributor

Problem

  • Have import validation set to 100%

During NZB import, the queue progress bar sits frozen at "Validating segments 30%" for the entire validation phase, then jumps straight to completed or failed. For incomplete files (segments missing on the provider) it can appear stuck for seconds to minutes, which is indistinguishable from a hang.

The 30% value is not real progress. It is a fixed stage marker set in internal/importer/processor.go right before validation begins:

proc.updateProgressWithStage(queueID, 30, "Validating segments")

Validation then owns the 30→100% band via a tracker created with CreateTracker(queueID, 30, 100). Real progress within that band is computed in internal/progress/tracker.go:

percentage = minPercent + (current * (maxPercent - minPercent) / total)
           = 30 + (current * 70 / total)

Root cause

In ValidateSegmentList, the progress counter only incremented after a successful Stat. A failed segment returned early and never reached the update:

_, err = usenetPool.Stat(checkCtx, seg.Id)
...
if err != nil {
    return fmt.Errorf("segment with ID %s unreachable: %w", seg.Id, err) // returns BEFORE progress update
}

if progressTracker != nil {
    count := atomic.AddInt32(&validatedCount, 1) // only reached on success
    progressTracker.Update(int(count), totalToValidate)
}

So when a file's articles are missing, validatedCount stays at 0 and the math resolves to 30 + 0*70/total = 30% for the whole run. The bar literally cannot move until a segment succeeds.

This matters because the pool is built with WithErrors().WithFirstError() and no context cancellation, so it STATs every selected segment even after the first failure. The work is happening; the UI just had no way to reflect it.

The change

Count every segment that has been checked (pass or fail) rather than only successes. The update is moved into a defer so it always fires when the goroutine returns, regardless of the Stat outcome.

Walkthrough the changes:

  1. validatedCount to checkedCount. The counter now tracks segments checked, not segments that passed. Renamed so the name matches the meaning.
  2. Progress update moved into a defer at the top of the closure. Deferring guarantees it runs on every return path, including the early return when Stat fails. This is the core of the fix.
  3. Error handling collapsed into a single if. With the success-side side effects (IncArticlesDownloaded / UpdateDownloadProgress) moved below the error check, the var err error / split if err == nil / if err != nil blocks are no longer needed. The unreachable-segment error return is unchanged.

Behavior change

Scenario Before After
Healthy file 30% until done, then jumps to 100% climbs 30→100% smoothly as segments are checked
Incomplete file frozen at 30% for the whole run, then fails climbs toward 100% as it checks, then fails

@evulhotdog evulhotdog marked this pull request as ready for review June 4, 2026 05:52
@javi11 javi11 merged commit 8d2d238 into javi11:main Jun 4, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants