From 9211d12e43a4eb48508126cfa748c72d44b2e8a9 Mon Sep 17 00:00:00 2001 From: Eric J Date: Wed, 29 Jul 2026 21:02:13 -0700 Subject: [PATCH 1/3] ci: add a verify workflow and Renovate config (first .github/ in repo history) `pnpm run verify` was the whole quality gate and it only ran when a human remembered to, or at deploy time - which can be days after the merge that broke it. `git log --all -- .github` was empty. Closes the structural half of issue #54. The workflow runs `pnpm run verify` verbatim rather than re-listing its three phases, so CI and local cannot drift into two definitions of "consistent". No refs:sync (needs a Factorio binary), no build step, no deploy, no secrets. Third-party actions are pinned to full commit SHAs with the release named in a trailing comment; permissions are `contents: read` only. Renovate over Dependabot because the holds here need encoding, not ignoring: typescript is disabled outright, pako carries a 14-day age and a note pointing at the byte-exactness invariant, wrangler + vitest-pool-workers are grouped because pool-workers hard-pins wrangler, and the brace-expansion override and `engines.node` floor are both marked not-a-stale-version. `minimumReleaseAge` is declared at 3 days specifically so Renovate can never propose a release fresh enough to make pnpm write a `minimumReleaseAgeExclude:` bypass. Config validated with `renovate-config-validator`. Renovate stays inert until the GitHub App is enabled on the repo. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01F3a2HLJ4beKARi7SPmaM54 --- .github/renovate.json5 | 122 +++++++++++++++++++++++++++++++++++ .github/workflows/verify.yml | 77 ++++++++++++++++++++++ 2 files changed, 199 insertions(+) create mode 100644 .github/renovate.json5 create mode 100644 .github/workflows/verify.yml diff --git a/.github/renovate.json5 b/.github/renovate.json5 new file mode 100644 index 00000000..0d51c09d --- /dev/null +++ b/.github/renovate.json5 @@ -0,0 +1,122 @@ +// Dependency automation for this repo (issue #54). Renovate, not Dependabot: +// several of this project's dependency decisions are deliberate HOLDS whose +// reasoning lives in CLAUDE.md prose, and Dependabot's `ignore` entries cannot +// express most of them. Everything below exists to stop a bot from cheerfully +// re-proposing, every week, the exact bump this project has already decided +// against - and to make the reason travel with the proposal when there is one. +// +// This file does nothing on its own. Renovate only acts once the Renovate +// GitHub App is enabled for the repository (https://github.com/apps/renovate). +// Validated with `renovate-config-validator` before landing. +// +// THE pnpm INTERACTION, which is the subtle part. +// This workspace relies on pnpm 11's built-in release-age cooldown - there is no +// `minimumReleaseAge` line in pnpm-workspace.yaml, the guard is a pnpm default. +// When pnpm is asked to install something newer than that cooldown allows it +// does not fail; it writes a `minimumReleaseAgeExclude:` bypass into +// pnpm-workspace.yaml, which is how `vue-tsc@3.3.8` once silently waived the +// guard. A dependency bot is a machine for producing exactly that situation. +// So `minimumReleaseAge` is declared HERE, explicitly, at a value comfortably +// above pnpm's default: Renovate must never open a PR for a release pnpm would +// want a bypass for. Declaring it also means a future pnpm changing its default +// cannot move this repo's floor silently. +// If `minimumReleaseAgeExclude:` ever appears in a Renovate PR's diff, that PR +// is wrong - do not merge it, fix the age rule instead. +{ + $schema: "https://docs.renovatebot.com/renovate-schema.json", + extends: [ + "config:recommended", + // Pin every GitHub Action to a commit SHA rather than a moving tag, and keep + // the `# vX.Y.Z` comment beside it updated. .github/workflows/verify.yml is + // already written that way by hand; this makes it the rule for anything + // added later, so the choice cannot drift action-by-action. + "helpers:pinGitHubActionDigests", + ], + + // See the pnpm interaction above. This is a floor, not a preference. + minimumReleaseAge: "3 days", + + // The central invariant here is byte-exactness against captured fixtures, and + // a green CI run is evidence of consistency, not of a bump being *correct* + // (`pnpm run verify` does not exercise every dependency - see the js-beautify + // note in pnpm-workspace.yaml). Nothing merges unread. + automerge: false, + + dependencyDashboard: true, + + // One weekly batch instead of a trickle. Times are UTC (no `timezone` set). + schedule: ["before 6am on monday"], + + packageRules: [ + { + // THE ONE THAT MATTERS MOST. Without it a bot proposes 6.0.3 -> 7.x every + // single week and someone re-derives the refusal every time (see #48, #52). + // TypeScript 7 exposes no programmatic API yet, the official migration is + // a dual-install alias, and vue-tsc/Volar cannot type-check .vue against + // it. Revisit at 7.1 deliberately, by hand. + matchPackageNames: ["typescript"], + enabled: false, + }, + { + // The codec's byte-exactness rests on `{ level: 9, legacyHash: true }`. + // `legacyHash` is a pako EXTENSION with no zlib-API contract, from a + // library that already flipped that default inside a single major (2.2.0 + // added it defaulting true, 3.0.0 flipped it false). A pako bump is a + // codec change until proven otherwise. + matchPackageNames: ["pako"], + minimumReleaseAge: "14 days", + automerge: false, + prBodyNotes: [ + "**Read `src/codec/deflate.ts` and the pako table in CLAUDE.md before merging.** Deflate must stay madler-zlib-compatible at level 9 and byte-exact against all 9 fixtures. `test/deflate.spec.ts` has a block that fails by name if `legacyHash` is dropped, renamed or re-defaulted - do not silence it by editing a fixture.", + ], + }, + { + // @cloudflare/vitest-pool-workers hard-pins an exact wrangler. Split PRs + // cannot resolve, so these two only ever move together. + matchPackageNames: ["wrangler", "@cloudflare/vitest-pool-workers"], + groupName: "cloudflare worker toolchain", + prBodyNotes: [ + "After merging, regenerate the worker types: `pnpm --filter @fmw/preview-worker exec wrangler types && pnpm vp check --fix`. The formatter pass is not optional.", + ], + }, + { + // `overrides.brace-expansion: 2.1.3` in pnpm-workspace.yaml is a + // deliberate maintenance-backport pin, not a stale version. Renovate would + // read it as three majors behind and propose 5.x, which is a spike into a + // dual-ESM/CJS package consumed by a CJS minimatch - explicitly rejected. + // The advisory's flat `<=5.0.7` range also means `pnpm audit` still flags + // 2.1.3 even though it carries the fix, so "the audit is red" is not a + // reason to take this bump. Read the comment in pnpm-workspace.yaml first. + matchPackageNames: ["brace-expansion"], + matchDepTypes: ["overrides", "pnpm.overrides"], + enabled: false, + }, + { + // `engines.node` is a deliberately permissive FLOOR (">=24.18.0"): older + // versions are untested, not known-broken. It is not a version to keep + // current. The version CI and development actually run on is + // `.node-version`, which Renovate may bump (see below). + matchDepTypes: ["engines"], + enabled: false, + }, + { + // `.node-version` became machinery, not documentation, the moment + // .github/workflows/verify.yml started feeding it to setup-node. Bumps are + // welcome but never unattended. + matchFileNames: [".node-version"], + prBodyNotes: [ + "This changes the Node version **CI** runs on, not just a local hint. Run `pnpm run verify` locally on the proposed version before merging.", + ], + }, + { + // vite-plus is pre-1.0 and is the entire static-check + test toolchain. + // Its tsgolint engine bumps have twice re-triggered the `TS2321: Excessive + // stack depth ... UserConfig` pathology in vite.config.ts, which looks + // like a type error in this repo and is not one. + matchPackageNames: ["vite-plus"], + prBodyNotes: [ + "If `vp check` starts reporting `TS2321: Excessive stack depth comparing types ... 'UserConfig'`, that is the known vite.config.ts comparison-depth pathology, not a real type error - see the type-checking section of CLAUDE.md for the `vue() as Plugin` cast that collapses it.", + ], + }, + ], +} diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml new file mode 100644 index 00000000..61f925af --- /dev/null +++ b/.github/workflows/verify.yml @@ -0,0 +1,77 @@ +# The whole quality gate, run automatically. Until this file existed, `pnpm run +# verify` only ran when a human remembered to (or at deploy time, which can be +# days after the breaking merge) - see issue #54. +# +# This job deliberately runs `pnpm run verify` VERBATIM rather than re-listing +# its three phases as separate steps. `verify` is the single definition of "the +# repo is consistent"; splitting it here would create a second definition that +# can silently drift from package.json. Note it is `verify`, not `check` - +# `check` is `vp check --fix` and CI must never rewrite files. +# +# What is deliberately NOT here: +# - `pnpm refs:sync`. It needs a Factorio binary and ~/GitHub/factorio-data, +# neither of which exists on a runner. `verify` is designed to pass with no +# Factorio installed and that property is what makes this workflow possible. +# - `pnpm vp build`. Not part of `verify`, and the build stamp reads git +# history, so it wants a checkout policy of its own. Tracked as a follow-up. +# - Any deploy step or credential. Cloudflare Pages does not build this repo +# (`deploy:app` uploads an already-built `dist`), so CI here is a check +# only and the job needs no secrets at all. +name: verify + +on: + push: + branches: [main] + pull_request: + # So a run can be forced without an empty commit. + workflow_dispatch: + +# Superseded pushes to the same PR are pointless at ~2 minutes a run. +concurrency: + group: verify-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +# Minimum scope: the job only reads the tree. It writes no statuses, comments, +# packages or releases, so nothing beyond `contents: read` is granted. +permissions: + contents: read + +jobs: + verify: + runs-on: ubuntu-latest + # `verify` is ~60-90s of work; 15 minutes is a hang detector, not a budget. + timeout-minutes: 15 + env: + # `preview:test` shells out to wrangler (`wrangler types --check`). Keep it + # from phoning home for telemetry on a runner where nobody can answer the + # opt-in prompt. + WRANGLER_SEND_METRICS: "false" + steps: + # Third-party actions are pinned to a full commit SHA, never a moving tag. + # The trailing comment names the release each SHA is, and Renovate updates + # the SHA and that comment together - see .github/renovate.json5. + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + # No `version:` input on purpose. pnpm/action-setup >= 6 reads + # `devEngines.packageManager` from package.json, so the pnpm pin stays in + # exactly one place. Hard-coding it here would be a second pin to drift. + # This step must precede setup-node: `cache: pnpm` below resolves the + # store path by running pnpm, so pnpm has to be on PATH already. + - uses: pnpm/action-setup@008330803749db0355799c700092d9a85fd074e9 # v6.0.9 + + # `.node-version` (26.5.0) is the single source of truth for the Node + # version, and this is its first real consumer - the file went from + # documentation to machinery when this workflow landed. `engines.node` + # stays a permissive floor and is deliberately NOT what CI runs. + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version-file: .node-version + cache: pnpm + + # A full workspace install. Anything narrower can leave a sibling + # workspace's symlink dangling and produce fake + # `TS2307: Cannot find module 'vitest'` errors; a real full install is the + # one that reports `Scope: all 3 workspace projects`. + - run: pnpm install --frozen-lockfile + + - run: pnpm run verify From 0458303f928603f9e11a4544e14f2fe969d587bf Mon Sep 17 00:00:00 2001 From: Eric J Date: Wed, 29 Jul 2026 21:35:12 -0700 Subject: [PATCH 2/3] test: raise testTimeout to 30s - the 5s default is what CI actually failed on The first CI run of the new workflow failed on exactly one test, and it was not a bug: `elevationRenderRequest.spec.ts`'s `view 'all' composites all five overlays` needs 9.8s on a 4-core GitHub runner (the whole suite is ~3x slower there - 230s vs 71s locally) against Vitest's 5s default. https://github.com/wormeyman/FactorioMapWebUI/actions/runs/30512820959 Raising the default rather than adding a 25th annotation. 24 individual tests across 10 files already carry an explicit `}, 120000)`, which is the same complaint made 24 times by hand, and elevationRenderRequest.spec.ts has 27 tests with zero annotations - so the annotation approach was already failing in its characteristic way, by depending on the next author remembering. 30s is ~3x the slowest measured case and still fails a genuine hang far inside the job's 15-minute cap; the existing 120000 annotations keep winning where they are set. No retries. These tests compare pixels against captured game output, so nothing here is nondeterministic - a retry could only hide a real regression. Also corrects two things this repo's docs asserted and CI disproved: - `verify` is ~65-90s locally and ~4 minutes on a runner, not the ~9.5s CLAUDE.md claimed. The gap is the point: 63s is where people start skipping a manual gate, which is half the argument for having CI at all. - `.node-version` is machinery now, not documentation - `setup-node` reads it, so it is the version the gate runs on. `engines.node` stays a permissive floor. The README also said "Requires Node 24.18.0 (see `.node-version`)", conflating the floor with the pin; `.node-version` says 26.5.0. Adds a CI section to CLAUDE.md (the conventions the workflow establishes, the Renovate/pnpm minimumReleaseAge interaction, and why branch protection is not configured here) and a verify badge + CI section to the README. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01F3a2HLJ4beKARi7SPmaM54 --- CLAUDE.md | 89 +++++++++++++++++++++++++++++++++++++++++++++++--- README.md | 24 +++++++++++--- vite.config.ts | 22 +++++++++++++ 3 files changed, 126 insertions(+), 9 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index d35e7d55..51369e4c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -130,10 +130,15 @@ bare `vp` or `npx vp` from the project root fails with `EBADDEVENGINES`. Node **26.5.0** (`.node-version`) is what the repo is developed and verified on. `engines.node` stays a permissive floor (`>=24.18.0`) rather than matching the -pin - older versions are simply untested, not known-broken. Nothing local -consumes `.node-version` (node comes from Homebrew, no version manager is -installed) and Cloudflare Pages never builds this repo - `deploy:app` uploads an -already-built `dist` - so the file is documentation, not machinery. +pin - older versions are simply untested, not known-broken. + +**`.node-version` is machinery now, not documentation.** That changed when +`.github/workflows/verify.yml` landed: `actions/setup-node` reads the file via +`node-version-file`, so it is what CI actually installs. Nothing _local_ consumes +it still (node comes from Homebrew, no version manager is installed) and +Cloudflare Pages never builds this repo - `deploy:app` uploads an already-built +`dist` - so an edit to it changes the version the gate runs on and nothing else. +Bump it only alongside a local `pnpm run verify` on the new version. Adding a root dependency needs `pnpm add -w` (or `--workspace-root`); a bare `pnpm add ` at the root fails with `ERR_PNPM_ADDING_TO_ROOT`. Prefer @@ -148,7 +153,11 @@ note below for why `pnpm up`'s transitive re-resolution can break `vp check`. step (see the type-checking note below; there is still **no** `vue-tsc` check of `.vue` bodies) - `pnpm vp build` - production build -- `pnpm run verify` - `vp check` + `vp test` + `preview:test` in one gate (~9.5s) +- `pnpm run verify` - `vp check` + `vp test` + `preview:test` in one gate. + **~65-90s on a dev machine, ~4 minutes on a CI runner** - the `~9.5s` this + line claimed for a long time was simply wrong, and the gap mattered: 63s is + exactly the duration at which people start skipping a manual gate, which is + half the argument for the CI workflow below. - `pnpm refs:sync` - pin `factorioLuaAPI/` + `~/GitHub/factorio-data` to the installed binary's version (`--check` reports drift only; `--fixtures` reports which oracle fixtures predate the binary). Deliberately **not** part of @@ -157,6 +166,76 @@ note below for why `pnpm up`'s transitive re-resolution can break `vp check`. - `pnpm run verify:deploy` - after deploying, confirm the live site is running local `HEAD` (see below). Takes an optional origin argument. +### CI (`.github/`) runs the same `verify`, and nothing else + +`.github/workflows/verify.yml` runs `pnpm run verify` on every pull request and +every push to `main`. It invokes the script **verbatim** rather than re-listing +its phases as separate steps, so there is exactly one definition of "this repo is +consistent" and CI cannot drift from local. If you change what `verify` means, +CI follows automatically - do not mirror the change into the YAML. + +Conventions that file establishes, and that anything added under `.github/` +should keep: + +- **Third-party actions are pinned to a full commit SHA**, with the release named + in a trailing `# vX.Y.Z` comment. Never a moving tag. + `helpers:pinGitHubActionDigests` in the Renovate config makes that automatic + for actions added later, and Renovate updates the SHA and the comment together. +- **`permissions:` is declared explicitly and minimally** (`contents: read`). Do + not fall back on the default token scope. +- **No `version:` input on `pnpm/action-setup`.** v6+ reads + `devEngines.packageManager` from `package.json`, so the pnpm pin lives in one + place. It must run _before_ `setup-node`, because `cache: pnpm` resolves the + store path by invoking pnpm. +- **No secrets, no deploy job.** Cloudflare Pages does not build this repo, so CI + is a check only. `pnpm refs:sync` is absent for the same reason it is absent + from `verify`: no runner has a Factorio binary. `pnpm vp build` is also absent + (the build stamp reads git history) - that is a known gap, not an oversight. + +`preview:test` needs **no Docker** on a runner, which was confirmed rather than +assumed: the worker tests are pool-workers (`workerd` arrives from npm) and the +container tests are `node --test` against `render.mjs`. + +**Renovate, not Dependabot** - `.github/renovate.json5`. The reason is that this +project's dependency decisions are _holds_ with reasoning behind them, and +Dependabot's `ignore` entries cannot express them; Renovate's `packageRules` + +`prBodyNotes` can, so the reasoning arrives attached to the proposal. `typescript` +is disabled outright, `pako` carries a 14-day age and a pointer at the +byte-exactness invariant, `wrangler` + `@cloudflare/vitest-pool-workers` are +grouped because pool-workers hard-pins wrangler, and the `brace-expansion` +override and `engines.node` floor are both marked as deliberate rather than stale. + +One interaction is worth knowing before touching that file. The workspace's +release-age guard is a **pnpm default**, not a line in `pnpm-workspace.yaml`, and +pnpm's response to being asked for something too fresh is to write a +`minimumReleaseAgeExclude:` bypass - which is how `vue-tsc@3.3.8` once waived it +silently. `minimumReleaseAge: "3 days"` is therefore declared in the Renovate +config, above pnpm's default, so Renovate can never propose a release pnpm would +want a bypass for. If `minimumReleaseAgeExclude:` appears in a bot PR's diff, +that PR is wrong; fix the age rule, don't commit the bypass. + +Renovate is inert until the GitHub App is enabled on the repo. Validate any edit +with `renovate-config-validator` (run it from outside the project root - a bare +`npx` here fails with `EBADDEVENGINES`). + +Branch protection on `main` is **not** configured. It is the natural follow-up +now that a check exists, but it is a repository setting rather than a file. + +#### `testTimeout` is 30s, deliberately, and retries are not used + +Vitest's 5s default was too tight for this suite long before CI existed - 24 +individual tests across 10 files carry an explicit `}, 120000)`, which is the +same complaint made 24 times by hand. The first CI run proved the default was the +real problem rather than any one test: on a 4-core runner (~3x slower, 230s vs +71s for the same suite) `elevationRenderRequest.spec.ts`'s `view 'all'` case +needs **9.8s**, and that file has 27 tests and zero annotations. `vite.config.ts` +now sets `testTimeout: 30_000`; the existing 120000 annotations still win over it. + +Do **not** reach for `retry` when a heavy render test fails in CI. Nothing here is +nondeterministic - these tests compare pixels against captured game output - so a +retry would only hide a genuine regression. A timeout means slow; read the +duration the reporter prints before assuming a hang. + ### Deploys are gated on `verify` Both deploy paths refuse to ship a broken tree. `deploy:app` runs diff --git a/README.md b/README.md index 0c8bca6c..282a0a50 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Factorio Map WebUI +[![verify](https://github.com/wormeyman/FactorioMapWebUI/actions/workflows/verify.yml/badge.svg?branch=main)](https://github.com/wormeyman/FactorioMapWebUI/actions/workflows/verify.yml) + A static SPA for authoring and exchanging Factorio 2.1.x map generation presets (exchange-string codec format `2.1.9.3`). The core editor has no backend - everything runs in the browser. An optional, opt-in map preview service (the app's only outbound call) @@ -73,15 +75,29 @@ docs). ## Development -Requires Node 24.18.0 (see `.node-version`) and the `vp` CLI (Vite+). The -project pins pnpm via `devEngines`, so run `vp` through pnpm (a bare `vp` or -`npx vp` from the project root fails with `EBADDEVENGINES`). +Built and verified on Node **26.5.0** (`.node-version`, which is also what CI +installs); `engines.node` is a permissive floor of `>=24.18.0` because older +versions are untested rather than known-broken. The project pins pnpm via +`devEngines`, so run `vp` through pnpm (a bare `vp` or `npx vp` from the project +root fails with `EBADDEVENGINES`). - `pnpm install` - install dependencies - `pnpm vp dev` - dev server -- `pnpm vp check --fix` - lint + format +- `pnpm vp check --fix` - lint + format + type-check - `pnpm vp test` - test suite (fixture-driven codec tests and UI tests) - `pnpm vp build` - production build +- `pnpm run verify` - the whole gate: `vp check` + `vp test` + `preview:test`. + ~65-90s locally. Needs no Factorio install. + +### CI + +`.github/workflows/verify.yml` runs `pnpm run verify` on every pull request and +every push to `main` - the same command, invoked verbatim, so CI and local cannot +disagree about what passing means. It needs no secrets and does not deploy. + +Dependency updates are handled by Renovate (`.github/renovate.json5`), which +encodes this project's deliberate holds rather than proposing them weekly - see +the CI section of `CLAUDE.md` for what is held and why. ## Map preview service diff --git a/vite.config.ts b/vite.config.ts index 949654b0..756fe0f4 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -53,6 +53,28 @@ export default defineConfig({ // App tests live in `test/`. Exclude `preview-service/**`, which has its own // Worker (pool-workers) and container (node:test) runners. include: ["test/**/*.spec.ts"], + // Vitest's 5s default is too tight for THIS suite, and that is not a new + // observation - 24 individual tests across 10 files already carry an + // explicit `}, 120000)` argument, which is the same statement made 24 times + // by hand. The tests that need it are the ones that render whole preview + // windows pixel-by-pixel and compare them against captured game output; + // being slow is what they are for, and there is nothing to optimise away. + // + // Raising the DEFAULT rather than adding a 25th annotation, because the + // annotation approach fails in a specific way: it depends on the author of + // the next heavy test remembering, and the symptom of forgetting is a + // timeout that reads like a hang. `test/elevationRenderRequest.spec.ts` has + // 27 tests and zero annotations; on a 4-core GitHub runner (~3x slower than + // a dev machine: 230s vs 71s for the same suite) its `view 'all' composites + // all five overlays` case needs 9.8s and failed the very first CI run. + // https://github.com/wormeyman/FactorioMapWebUI/actions/runs/30512820959 + // + // 30s is ~3x the slowest measured case, so it absorbs runner variance while + // still failing a genuine hang in well under the job's 15-minute cap. It is + // a floor, not a ceiling: the existing 120000 annotations still win where + // they are set. Retries were deliberately NOT used - a retry would hide a + // real flake, and nothing here is actually flaky, just slow. + testTimeout: 30_000, }, // Never reformat the byte-verified spec docs or the read-only fixture // ground truth - `vp check --fix` would otherwise rewrite them on every run. From 59b048081f4e4e6cf81632f8f920df0a6d925891 Mon Sep 17 00:00:00 2001 From: Eric J Date: Wed, 29 Jul 2026 21:51:50 -0700 Subject: [PATCH 3/3] fix(renovate): drop a matchDepTypes narrowing that could match nothing The brace-expansion hold was scoped with `matchDepTypes: ["overrides", "pnpm.overrides"]`, which is a guess: the override lives in pnpm-workspace.yaml rather than package.json, and if the depType Renovate reports for that location is neither string the rule matches nothing and the hold silently does not exist. `renovate-config-validator` cannot catch that - the config is valid, just inert. brace-expansion appears in no manifest in this repo (it is a transitive of js-beautify via @vue/test-utils), so matching by package name alone is both correct and the only form that cannot miss. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01F3a2HLJ4beKARi7SPmaM54 --- .github/renovate.json5 | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 0d51c09d..c62d5a05 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -87,8 +87,15 @@ // The advisory's flat `<=5.0.7` range also means `pnpm audit` still flags // 2.1.3 even though it carries the fix, so "the audit is red" is not a // reason to take this bump. Read the comment in pnpm-workspace.yaml first. + // + // Deliberately NOT narrowed with `matchDepTypes: ["pnpm.overrides"]`. The + // override lives in pnpm-workspace.yaml, not package.json, and if the + // depType Renovate reports for that location is anything other than the + // string guessed here the rule would silently match nothing - a config bug + // no validator can catch. brace-expansion appears in no manifest in this + // repo (only as a transitive of js-beautify), so matching it by name alone + // is both correct and the only form that cannot miss. matchPackageNames: ["brace-expansion"], - matchDepTypes: ["overrides", "pnpm.overrides"], enabled: false, }, {