Skip to content

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

@shaun0927

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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions