The soak window
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:
| Surface | Key | Units |
|---|---|---|
.cargo/config.toml |
global-min-publish-age (nightly-only feature; inert on perry's stable toolchain) |
"N days" |
tools/pnpm-workspace.yaml |
minimumReleaseAge |
minutes |
.npmrc |
min-release-age |
days |
tools/taze.config.mts |
maturityPeriod |
imports SOAK_DAYS |
external-tools.json |
soakBypass annotations |
days |
.github/dependabot.yml |
cooldown.default-days per update block |
days |
Commands (package.json scripts — the code lives in scripts/soak/)
npm run soak— parity-check every surface (CI-gated:soak-gatejob in security-audit.yml, always-run)npm run soak:fix— rewrite drifted windows, prune expired exclusionsnpm run deps:update— bump npm (taze) + cargo deps through the windownpm run tools:check/tools:fix/tools:install— validate / prune-expired-bypasses / install the SRI-pinned external tools (external-tools.json);tools:installalso writes the sfw firewall shims into the dev-tools bin dirnpm run test:scripts— the scripts' own unit tests
The gates fail closed when a bypass window clears, but nobody has to
watch for that: 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 npm run soak and npm run test:scripts
both exit 0 — the same gates CI runs. Re-run them after every fix.
Change the window (one place)
- Edit
SOAK_DAYSinscripts/soak/constants.mts. npm run soak:fix(rewrites cargo/npmrc/yaml and drifted dependabot values; taze follows by import). A dependabot block with NO cooldown at all is a check finding fixed by hand — add the two lines where the finding says.npm run soak+npm 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, 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, npm 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.
Maintaining this skill
scripts/soak/ is the law; this file only documents it — when they
disagree, fix this file. When editing, follow Anthropic's guidance:
- Prompting best practices
- Prompting Claude Fable 5
- Skill authoring best practices
- Write an effective CLAUDE.md
Keep it concise (goal + constraints, not step enumeration), keep the
description in third person with explicit "use when" triggers, and keep
the window value in constants.mts rather than restating it here.