Skip to content

Span.Progress returns Count > Total when a running child has Total == 0 (follow-up to #1208) #1241

Description

@shaun0927

Gorse version

master (HEAD b7e6aa9, 2026-04-16). The relevant code lives at common/monitor/progress.go:138-169, introduced in #1208.

Describe the bug

After #1208 removed the divide-by-zero panic, the "zero-total child is complete" fallback can push parentCount above parentTotal when:

  • the parent has already consumed its own count (s.count == s.total), and
  • a running child is reporting Total == 0.

With a parent total=2, count=2 and one running zero-total child:

childTotal   (max, fallback)     = 1
parentTotal  = s.total * childTotal = 2
parentCount  = s.count * childTotal = 2
             + childTotal  (zero-total child branch) = 3
-> Progress{Count: 3, Total: 2}   // 150%

The dashboard progress bar (/api/dashboard/tasks) consumes this value directly and renders >100%.

To Reproduce

// common/monitor/progress_overflow_test.go
package monitor

import (
    "context"
    "testing"
)

func TestProgress_ZeroTotalChildExceeds100Percent(t *testing.T) {
    _, parent := Start(context.Background(), "parent", 2)
    parent.Add(2)

    ctx := context.WithValue(context.Background(), spanKeyName, parent)
    _, _ = Start(ctx, "child", 0)

    got := parent.Progress()
    t.Logf("parent.Progress() -> Count=%d Total=%d", got.Count, got.Total)
    if got.Count > got.Total {
        t.Fatalf("Count (%d) exceeds Total (%d)", got.Count, got.Total)
    }
}

go test -run TestProgress_ZeroTotal -v ./common/monitor/... fails on HEAD with Count (3) exceeds Total (2).

Expected behavior

Progress.Count <= Progress.Total for every combination of parent/child totals.

Additional context / suggested fix

A one-line clamp before returning:

if parentCount > parentTotal {
    parentCount = parentTotal
}
return Progress{..., Count: parentCount, Total: parentTotal, ...}

PR with the clamp + regression test is being opened against this issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions