The soak window

SkillProductivity

Lets your agent manage a repo's supply-chain soak window, including checking derived files and adding package exclusions.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the The soak window skill

About this capability

Manages the repo's supply-chain soak window (SOAK_DAYS) — checks and fixes the derived surfaces, bumps or disables the window, adds dated per-package exclusions, and bumps pinned external tools. Use when a task touches minimumReleaseAge, min-release-age, min-publish-age, external-tools.json, renovat

What this skill tells your AI

The instructions your AI receives, as published by nubjs/nub in .claude/skills/soak/SKILL.md and read by ahel’s review.

One rule: a release must be at least SOAK_DAYS old before this repo adopts it. The delay gives the ecosystem time to catch a malicious or yanked release before we ever install it. The window is defined exactly once — read the current value from scripts/soak/constants.mts and never hardcode it elsewhere. Every surface derives from or is parity-checked against it:

SurfaceKeyUnits
.cargo/config.tomlglobal-min-publish-age"N days"
tools/pnpm-workspace.yamlminimumReleaseAgeminutes
.npmrcmin-release-agedays
tools/taze.config.mtsmaturityPeriodimports SOAK_DAYS
external-tools.jsonsoakBypass annotationsdays
.github/renovate.jsonminimumReleaseAge (explicit — an extends: preset doesn't count)"N days"

Commands (package.json scripts — the code lives in scripts/soak/)

  • pnpm run soak — parity-check every surface (CI-gated in docs-links)
  • pnpm run soak:fix — rewrite drifted windows, prune expired exclusions
  • pnpm run deps:update — bump npm (taze) + cargo deps through the window
  • pnpm run tools:check / tools:fix / tools:install — validate / prune-expired-bypasses / install the SRI-pinned external tools (external-tools.json)
  • pnpm run test:scripts — the scripts' own unit tests

The gates fail closed on invalid states (missing, malformed, or wrong-arithmetic annotations) and WARN on expired ones — stale is not unsafe, and nobody has to watch for it: the scheduled soak-autofix workflow runs soak:fix + tools:fix daily and commits the pruning as a bot PR.

A soak change is done when pnpm run soak and pnpm run test:scripts both exit 0 — the same gates CI runs. Re-run them after every fix.

Change the window (one place)

  1. Edit SOAK_DAYS in scripts/soak/constants.mts.
  2. pnpm run soak:fix (rewrites cargo/npmrc/yaml; taze follows by import).
  3. pnpm run soak + pnpm run test:scripts — existing exclusion annotations encode the old window and will be flagged; re-date or remove them, then re-run until both pass.

Opt out entirely: set SOAK_DAYS = 0 and run the same two steps — cargo, pnpm/nub (minimumReleaseAge: 0), npm, and taze all treat zero as disabled. There is deliberately no env-var bypass: opting out is a committed, reviewable change, never a silent one.

Skip the soak for ONE package (dated, temporary)

Add to minimumReleaseAgeExclude in tools/pnpm-workspace.yaml with the annotation on the line above (block list only — flow [..] is rejected because a comment line can't attach to an inline entry):

# published: YYYY-MM-DD | removable: YYYY-MM-DD
- 'name@1.2.3'

removable = published + SOAK_DAYS; published must be the real registry publish date (the placeholders above are schematic — copying them verbatim is rejected). Once removable passes, pnpm run soak warns until the pin is pruned (soak:fix or the soak-autofix workflow does it). Bare names / @scope/* globs are standing trust and need no annotation. External tools use the same shape via a soakBypass object in external-tools.json.

The cargo soak needs nightly — the repo still must not pin one

min-publish-age is an [unstable] cargo feature: a stable cargo ignores it silently. The repo deliberately ships no rust-toolchain.toml, because a repo-root toolchain file outranks rustup default and would silently redirect the version-pinned CI jobs (the MSRV Check legs) and build released binaries on nightly.

The nightly is instead requested per-invocation, at the only step that picks versions: scripts/soak/update-deps.mts runs cargo +nightly update. Everything else — every CI job, every shipped binary — builds on stable. If you need the cargo soak somewhere new, call cargo +nightly there; do not add a toolchain file.

Keep the nightly current — a merely-old one silently disables the window. Cargo treats an [unstable] key it does not implement as a warning and exits 0, so an old nightly resolves with NO window while looking successful. Measured both sides: nightly 2026-03-21 (cargo 1.96.0-nightly) has no such -Z and skips the window silently; nightly 2026-07-27 (cargo 1.99.0-nightly) supports -Z min-publish-age and visibly holds a too-fresh release back (available: v0.2.189, published 7 days ago). deps:update detects the warning and fails with the fix (rustup update nightly) — if you see it, the lockfile changes it just made are unsoaked.

Maintaining this skill

scripts/soak/ is the law; this file only documents it — when they disagree, fix this file. Keep it concise (goal + constraints, not step enumeration), and keep the window value in constants.mts rather than restating it here.

Signals

GitHub stars
4k
Forks
60
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
soak
Source
github.com/nubjs/nub