The problem
The cooldown and the staleness check reach Docker Hub images only. The README gives the same reason under both: other registries "expose no publication date, so images there are updated without a cooldown, and a cooldown marker on one of them is reported as redundant." An image on ghcr.io or mcr.microsoft.com is therefore adopted the moment a new tag appears, however fresh, and is never reported as stale however long its tag has sat unrebuilt.
An OCI registry does expose a date: the image config blob carries a created timestamp. Probed 2026-08-15, using Update-time's own registry authentication (oci._auth_headers, which performs the WWW-Authenticate challenge) and following the index manifest to an image manifest and then to its config blob:
| Image |
created |
ghcr.io/astral-sh/uv:0.9.7 |
2025-10-30T21:26:01Z |
mcr.microsoft.com/dotnet/runtime:8.0 |
2026-08-10T16:56:43Z |
gcr.io/distroless/static-debian12:latest |
1970-01-01T00:00:00Z |
Two of the three are the dates you would expect, and the third is the constraint this issue has to solve rather than a reason to abandon it.
The design constraint
created records when the image was built, not when it was pushed, and a reproducible build fixes it: distroless reports the Unix epoch. Read naively, that image is more than fifty years stale and past every cooldown that could ever be set — the staleness check would warn about the most actively maintained base image in the table above. Docker Hub's push date has no such failure mode, because the registry stamps it rather than the build.
So the date needs a credibility test before it can drive either check, and a date that fails it has to mean "unknown" rather than "very old" — which is what Update-time already does for a reference whose source reports no date at all.
The cost
Reading the date costs requests. Resolving a digest today fetches one manifest; a date needs the index manifest, one image manifest named by it, and the config blob, so two more requests per tag examined. The token is already fetched for the digest.
The cooldown multiplies that. It is not asked once per image but once per candidate tag, since Update-time walks candidates from the newest down until one is past the cooldown. On Docker Hub this is free, because the tag listing carries every tag's push date in a single response. Outside Docker Hub each candidate examined would cost its own manifest and blob, and an image whose newest tags are all within the cooldown window pays that for each of them.
Scope
- Read the created date for an image on any OCI registry, and feed it to the cooldown and the staleness check that Docker Hub images already get.
- Decide what makes such a date credible, and treat one that fails that test as no date at all, leaving the image updated without a cooldown and unreported for staleness, exactly as today.
- Stop reporting a
stale or cooldown marker on an image outside Docker Hub as redundant, since the scope would then hold something back.
Out of scope
- Docker Hub images, which already answer both questions from the tag listing in one request.
- CircleCI machine-executor images, which no registry serves, so both scopes stay redundant there.
Documentation
- The per-type "Cooldown" and "Stale dependencies" answers for Docker images, both of which name Docker Hub as the limit.
- The Docker-image rows in the dependency-type tables under "Cooldown" and "Stale dependencies".
- "Setting a staleness threshold" and "Setting a cooldown period", which name an image on a registry other than Docker Hub as one of the three kinds of reference whose marker is reported as holding nothing back, and "Redundant markers", which points at that list.
- A changelog entry under
[Unreleased].
Open questions
- What test makes a
created date credible? Treating the epoch as unknown covers distroless, but a build that sets SOURCE_DATE_EPOCH to its commit date produces a plausible-looking date that is equally not a publication date.
- Is the extra manifest and blob per candidate tag acceptable for the cooldown, or should the cooldown outside Docker Hub be applied to the chosen tag alone — adopting it or holding it back, rather than walking down to the newest eligible one?
- When the config blob carries no
created, is the manifest's org.opencontainers.image.created annotation worth falling back to, or does it carry the same reproducible-build caveat?
The problem
The cooldown and the staleness check reach Docker Hub images only. The README gives the same reason under both: other registries "expose no publication date, so images there are updated without a cooldown, and a
cooldownmarker on one of them is reported as redundant." An image onghcr.ioormcr.microsoft.comis therefore adopted the moment a new tag appears, however fresh, and is never reported as stale however long its tag has sat unrebuilt.An OCI registry does expose a date: the image config blob carries a
createdtimestamp. Probed 2026-08-15, using Update-time's own registry authentication (oci._auth_headers, which performs theWWW-Authenticatechallenge) and following the index manifest to an image manifest and then to its config blob:createdghcr.io/astral-sh/uv:0.9.72025-10-30T21:26:01Zmcr.microsoft.com/dotnet/runtime:8.02026-08-10T16:56:43Zgcr.io/distroless/static-debian12:latest1970-01-01T00:00:00ZTwo of the three are the dates you would expect, and the third is the constraint this issue has to solve rather than a reason to abandon it.
The design constraint
createdrecords when the image was built, not when it was pushed, and a reproducible build fixes it: distroless reports the Unix epoch. Read naively, that image is more than fifty years stale and past every cooldown that could ever be set — the staleness check would warn about the most actively maintained base image in the table above. Docker Hub's push date has no such failure mode, because the registry stamps it rather than the build.So the date needs a credibility test before it can drive either check, and a date that fails it has to mean "unknown" rather than "very old" — which is what Update-time already does for a reference whose source reports no date at all.
The cost
Reading the date costs requests. Resolving a digest today fetches one manifest; a date needs the index manifest, one image manifest named by it, and the config blob, so two more requests per tag examined. The token is already fetched for the digest.
The cooldown multiplies that. It is not asked once per image but once per candidate tag, since Update-time walks candidates from the newest down until one is past the cooldown. On Docker Hub this is free, because the tag listing carries every tag's push date in a single response. Outside Docker Hub each candidate examined would cost its own manifest and blob, and an image whose newest tags are all within the cooldown window pays that for each of them.
Scope
staleorcooldownmarker on an image outside Docker Hub as redundant, since the scope would then hold something back.Out of scope
Documentation
[Unreleased].Open questions
createddate credible? Treating the epoch as unknown covers distroless, but a build that setsSOURCE_DATE_EPOCHto its commit date produces a plausible-looking date that is equally not a publication date.created, is the manifest'sorg.opencontainers.image.createdannotation worth falling back to, or does it carry the same reproducible-build caveat?