utils/dependency-freshness.allowlist.yaml
Krzysztof kuhy Rudnicki 1439c0f5c0 Make the allowlist inheritable, and cache the quarantine lookups
Two things that were fine in utils and would not have been in the next forty
repos.

**The allowlist is now fleet-wide plus per-repo.** `typescript-eslint` blocks
TS 7 in EVERY repo that pins typescript -- eight of them and counting -- and a
repo-only allowlist meant hand-copying one entry into eight files that then rot
independently. That is the four-way fork of the 250-line cap, reproduced inside
the mechanism built to avoid it. `~/utils/dependency-freshness.allowlist.yaml`
is inherited by every repo; a repo entry for the same `ecosystem:package`
overrides it.

Inherited entries are exempt from the no-longer-needed check everywhere except
the repo that owns the file. Without that carve-out a fleet-wide hold on
typescript exits 2 in every Flutter app -- it excuses nothing there, which is
the normal case, not rot -- and those repos become uncommittable. Confirmed
against punchme, which now exits 0 while utils still reports the entry as in
use.

**`quarantine.py` bypassed the cache entirely.** It ran for every npm finding
and fetched the FULL packument -- 7MB for react, 16MB for typescript -- with no
TTL and no reuse, inside a pre-commit hook. One finding in utils, but the JS
repos ahead have 16 to 37 each. Now cached under the normal 6h TTL, keyed
`<name>@<dist-tag>`: the tag has to be part of the key rather than clamped
afterwards, because clamping returns the ceiling and the ceiling is frequently
the very release the quarantine is excluding.

**Both cache and shared allowlist are now redirected by AUTOUSE fixtures.** A
quarantine test had already seeded a fake answer for package "x" into the real
~/.cache/dep-freshness/registry.json, and the next run read its own pollution
back and passed for the wrong reason. Removed the entry; the fixture makes it
unrepeatable.

292 tests, 100% branch coverage on every module.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CRykabMwPgDzFHcARoqpaK
2026-08-28 13:58:44 +02:00

40 lines
1.8 KiB
YAML

# Dependencies deliberately held below latest stable, and why.
#
# THIS IS THE FLEET-WIDE FILE. Every repo inherits it; a repo's own
# dependency-freshness.allowlist.yaml adds to it, and an entry there for the
# same ecosystem:package overrides the one here. A blocker like "typescript-eslint
# does not support TS 7" holds in every repo that pins typescript, and copying
# it into eight of them would give eight entries that rot independently.
#
# Two entry classes, and the distinction is load-bearing:
#
# blocked_by: transitive:<pkg>@<ver>
# A PREDICATE. The gate re-evaluates the blocker on every run and the
# entry clears itself the moment upstream moves. It must NOT carry
# `expires` -- a calendar date nobody can act on only turns the gate red
# for a reason no commit can fix.
#
# anything else
# Discretionary. Requires `expires`, capped at 90 days, and fails once
# past.
#
# Every entry prints loudly on every gate run and at session start. An
# exception nobody sees any more is a suppression.
exceptions:
- ecosystem: npm
package: typescript
pinned: "6.0.3"
latest_known: "7.0.2"
reason: >-
typescript-eslint 8.68.0 -- itself the latest release -- declares
`typescript: ">=4.8.4 <6.1.0"` and throws "typescript-eslint does not
support TS 7.0" when eslint loads its config. No 9.x exists. Taking TS 7
would mean dropping every type-aware lint rule from every repo that pins
it, so the compiler waits for the linter.
Held fleet-wide: this blocks ts_core, web_ui, konbini-67, iron-and-anvil,
awesome-mcp-explorer, europe-county-map and every other repo pinning
typescript, which is exactly why the entry lives here and not in eight
separate files.
blocked_by: "transitive:typescript-eslint@8.68.0"