Dependency Release Cooldown Admission Ledger
Pricing
from $12.00 / 1,000 run_starteds
Dependency Release Cooldown Admission Ledger
Check each pinned dependency version against a release-age cooldown policy. Report which pins are still inside the window, and the date on which each one becomes admissible.
Pricing
from $12.00 / 1,000 run_starteds
Rating
0.0
(0)
Developer
kingii98
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Dependency Release Cooldown Admission Ledger for Mixed Ecosystems
Check each pinned dependency version against a release-age cooldown policy. The Actor reports which pins are still inside the cooldown window, and the date on which each one becomes admissible.
A cooldown policy says: do not adopt a release until it is at least N days
old. uv applies such a policy with its exclude-newer setting, and other
tools block fresh releases by default. Other ecosystems have no such setting:
the Maven versions plugin, for example, has no release-age filter. This Actor
applies one policy across npm, PyPI, Maven Central and NuGet, and gives the
part that the native tools leave out: the date on which each blocked pin
becomes admissible. A blocked list is a stop sign; a dated calendar is a plan.
What it does
- Reads a bounded list of pins in the form
ecosystem:name@version. - Asks each package registry for the release record of the package.
- Compares the publish timestamp of the pinned version with the as-of date.
- Writes one dataset row for each pin, one run summary, and one admission calendar when at least one pin is blocked.
The verdict is a function of three values only: the publish timestamp, the as-of date and the cooldown in days. The Actor holds no state between runs, so a run made today with an as-of date of last month gives the same answer as the run made last month. That is what an audit needs.
Input
| Field | Type | Default | Meaning |
|---|---|---|---|
pins | array of text | five example pins | 1 to 1000 pins, each one ecosystem:name@version. One entry may hold several lines. |
cooldownDays | integer | 30 | A release younger than this many days at the as-of date is inside the window. 0 to 3650. |
asOf | text | run date | The date the policy is applied, YYYY-MM-DD. The field has no schema default: an omitted or empty asOf is always the run date, which is what a scheduled run needs. |
exemptPackages | array of text | ["lodash"] | Names the policy does not cover, for example first-party packages. |
Every field has a default, so a run with an empty input {} succeeds.
Pin format
| Ecosystem | Prefix | Example |
|---|---|---|
| npm | npm | npm:express@4.18.2, npm:@babel/core@7.24.0 |
| PyPI | pypi | pypi:requests@2.31.0 |
| Maven Central | maven | maven:com.google.guava:guava@32.1.3-jre |
| NuGet | nuget | nuget:Newtonsoft.Json@13.0.3 |
A Maven pin names the group and the artifact, separated by a colon. The
aliases node, pip, python, maven-central, java and dotnet are
accepted as well.
An exemption matches without regard to case, in the registry spelling or in
the normalized spelling (Flask_SQLAlchemy matches flask-sqlalchemy). For a
Maven pin the artifact alone also matches. Write ecosystem:name, for example
npm:express, to exempt the package in one ecosystem only.
Output
One dataset row for each pin (recordType pin):
| Field | Meaning |
|---|---|
pin | The pin as the buyer wrote it. |
ecosystem, packageName, version | The three parts of the pin. |
publishedAt | The publish timestamp from the registry release record. |
ageDays | The age of the release at the as-of date. It is negative when the release is newer than the as-of date. |
cooldownDays | The policy this run applied. |
verdict | See the table below. |
admissibleOn | The date the pin leaves the window. For an admissible pin it is the date it left the window, which an audit can read. |
daysRemaining | Days from the as-of date to admissibleOn, 0 for an admissible pin. |
newestAdmissibleVersion | The highest release that already satisfies the policy at the as-of date. |
newestAdmissiblePublishedAt | The publish timestamp of that release. |
asOf, note | The date applied, and the reason when a verdict needs one. |
| Verdict | Meaning |
|---|---|
admissible | The release is at least cooldownDays old at the as-of date. |
inside_cooldown | The release is younger than the policy allows. admissibleOn says when that ends. |
unknown_publish_date | The registry has no publish date for this version: the package or the version is not found, or the registry call failed. note says which. |
exempt | The package is on the exempt list, so the policy is not applied and no registry call is made. |
invalid_pin | The entry could not be read. note says why. The run continues. |
One run-summary row (recordType runSummary) holds countsByVerdict, the
count per ecosystem, earliestAdmissionDate (the first date on which any
blocked pin becomes admissible) and fullSetAdmissibleOn (the date on which
the whole set becomes admissible).
One admission-calendar row (recordType admissionCalendar) groups the
blocked pins by the date on which each becomes admissible. It is written only
when the run finds at least one blocked pin, and it is also stored in the
key-value store under the key admission-calendar.
A blocked pin, an unreachable registry and an empty pin list are business results. They are reported in the dataset and in the run status message, and the run succeeds. A failed run means a real malfunction.
Pricing (pay per event)
| Event | Unit | Counted as |
|---|---|---|
run_started | one run | Charged once at the start of every run, before the input is read, so that a run stopped early still pays for the work it started. |
pin_checked | one pin checked | One unit for each pin checked against the policy. An exempt pin and an unreadable pin are not checked, so they are not charged. A pin with an unknown publish date is charged, because the registry lookup was made. |
admission_calendar_built | one run with blocked pins | Charged once, and only for a run that finds at least one blocked pin and therefore builds the calendar. |
Two pins of one package cost one registry call, which keeps the run cost below the charge.
Bounds and safety
- At most 1000 pins and 500 exempt names in one run.
- Only four fixed hosts are contacted:
registry.npmjs.org,pypi.org,search.maven.organdapi.nuget.org. No host, scheme or path comes from the input, so the Actor sends no request to a private or reserved address. The one URL a registry itself supplies, a NuGet registration page, is used only when it stays onapi.nuget.org. - 25 s timeout for each call, at most 6 calls in parallel, at most 12 MB for each response body.
- HTTP only. No browser, no proxy, no login and no secret.
- A registry failure for one package is reported on that package's rows. It does not end the run.
Version 1 limitations
- Version ordering uses one rule for the four ecosystems: the numeric parts
are compared as numbers, a stable release sorts above its own prereleases,
and the remaining text is compared as text. A Maven classifier-style suffix
such as
-jreis not read as a prerelease marker, but two such suffixes on one version number are ordered as text. newestAdmissibleVersionleaves out prereleases, unless the pin itself is a prerelease, and always leaves out a yanked or unlisted release.- Maven Central is read through the search API. The run asks for each pinned version exactly, then reads the 200 newest releases of the coordinate for the newest-admissible answer.
- A NuGet package with many registration pages is read to a bound: the pages that hold a pinned version first, then the newest pages, at most 6 fetched pages.
- The publish timestamp is the one the registry states. A registry that restates a release changes the answer.
Repeat use
The result changes without any action by the buyer, because a pin that is
blocked today is admissible tomorrow. Run the Actor on a daily or weekly
schedule and read fullSetAdmissibleOn to plan the merge window.
Development
uv syncuv run pytestuv run ruff check .
To run the Actor against the default fixture:
mkdir -p storage/key_value_stores/defaultcp .actor/default_input.json storage/key_value_stores/default/INPUT.jsonAPIFY_LOCAL_STORAGE_DIR=$PWD/storage uv run python -m cooldown_ledger
The default input states a fixed as-of date, so the example run gives the same
answer on every day: three admissible pins, one pin inside the window with an
admission date, and one exempt pin. Only this fixture holds that date. A run
that does not state asOf uses the run date.