# What should a progress percentage mean for a job that discovers more work as it runs?

> Report progress against known or estimated work, label the basis, and use phase counters or an indeterminate state when the total can grow.

Canonical URL: https://www.devobs.io/articles/qa-fanout-job-progress/
By: Arjun Shah
Published: 2025-07-05T05:23:43.300Z
Updated: 2026-09-06T10:18:15.722Z
Section: Architecture

A progress percentage for a job that discovers more work should mean **progress against the work currently known or credibly estimated**, not a fake promise about the final total. If the denominator can grow, do not freeze it up front. Report phase, completed units, and whether the total is known. Show a percentage only when it is honest; otherwise mark the operation indeterminate and keep updates monotonic and useful. That aligns with accessible progress semantics in [MDN’s progressbar role reference](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/progressbar_role) and with [long-running operation](https://www.devobs.io/articles/long-running-operation-api-contracts/) metadata guidance in [Google AIP-151](https://google.aip.dev/151).

## What should the percentage actually represent?

Use this contract:

- `phase`: what kind of work is happening now.
- `completed`: durable units finished.
- `known_total`: total units currently discovered.
- `estimated_total`: optional forecast of final units.
- `percent`: only derived from `known_total` or `estimated_total`, with the basis named.
- `indeterminate`: true when no honest denominator exists.

The key rule is that `completed` must never go backwards. `known_total` may increase as the system discovers more work. That means a percentage based on known work can stall or even dip if you recompute it naively. Avoid that UI surprise by tying percentages to phases, not pretending the whole job was measurable from the start.

For APIs, put these fields in operation metadata. [Google AIP-151](https://google.aip.dev/151) explicitly says metadata is for information such as progress and partial failures on each operation poll.

## How should a fan-out job report progress across phases?

Split the job into explicit phases with separate semantics.

Example: import a folder, parse manifests, then process each discovered file.

1. **Discovery phase**
   - Status: `Discovering files`
   - Percentage: indeterminate
   - Counters: `directories_scanned=120`, `files_discovered=3,240`

2. **Processing phase**
   - Status: `Processing files`
   - Percentage: determinate against discovered work
   - Counters: `files_processed=810`, `known_total=3,240`, `percent=25`

3. **Late fan-out phase** if processing a file can enqueue more files
   - Keep `completed` monotonic.
   - If new files are found, increase `known_total` and say so in status text: `Processing files; discovered 140 additional files`.
   - If that changing denominator would confuse users, switch the percentage label to `25% of discovered work processed` rather than `25% complete`.

For UI and accessibility, this distinction matters. [MDN’s progressbar role reference](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/progressbar_role) says `aria-valuenow` should be omitted when the value is indeterminate, and recommends `aria-valuetext` when a plain percentage would be misleading.

## When should you show an estimate instead of exact progress?

Show an estimate only if you can explain its basis and keep it stable enough to help. Good examples are batched imports where historical averages make final file count predictable, or tree walks where the frontier size gives a reasonable forecast.

A solid pattern is:

- `percent_known = completed / known_total`
- `percent_estimated = completed / estimated_total`
- expose one of them, labeled clearly

If you choose an estimate, never present it as exact completion. Call it `estimated progress` and keep the raw counters visible for engineers and operators.

## What are the limits of this contract?

This approach fits long-running jobs with meaningful units of work: files, records, partitions, child tasks. It is less useful for jobs dominated by a few highly variable steps, such as one huge database rewrite followed by a tiny cleanup phase. In those cases, phase status and milestone events are more truthful than a percentage.

Also, define the ordering boundary carefully: only count a unit as complete after the system has durably recorded the result for that unit. Do not increment `completed` on a preflight check or before the write that makes the result observable.

## Follow-up: What if users insist on a single percentage?

Give one, but name it honestly: `estimated overall progress` or `progress on discovered work`. Pair it with phase text so the number is not carrying all meaning.

## Follow-up: Should percent ever go backwards?

Prefer no. Keep the displayed percent monotonic by phase, or switch to indeterminate during denominator growth. Raw counters may change; the top-line indicator should stay understandable.

Next step: define your operation metadata schema first, then decide which phases are determinate, which are indeterminate, and what exact event makes a work unit count as completed.

Reviewed: 2026-09-05

## Source references

- <https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/progressbar_role>
- <https://google.aip.dev/151>
