Skip to content

nuxt-cloudflare: ESLint result cache in the Fast lane; record why the skipped Fast name stays - #176

Merged
loganrenz merged 1 commit into
mainfrom
eslint-cache-names
Sep 30, 2026
Merged

loganrenz merged 1 commit into
mainfrom
eslint-cache-names

Conversation

@loganrenz

@loganrenz loganrenz commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

What

Task 2 (done): ESLint result cache in the Fast lane. New input eslint-cache (default true).
A preload (NODE_OPTIONS=--require, exported only inside the Run fast scripts step) appends
--cache --cache-location <dir>/ --cache-strategy content to any process whose entry script is eslint's own
bin/eslint.js, however it was reached (pnpm --filter web run lint, turbo run lint, a wrapper).
It leaves everything else alone: other programs, --print-config (the typegen script), --version, and an
eslint that already passes --cache*. A caller whose lint script is not eslint is untouched.

  • Why a preload: the apps' lint scripts are wrappers (pnpm --filter web run lint, turbo run lint,
    node scripts/lint-budget-guard.mjs ...), so appending flags to the script is wrong (turbo run lint --cache
    is turbo's own flag), and ESLint has no env var for its cache. NODE_OPTIONS is the one variable turbo's strict
    env mode passes to tasks (checked against turbo 2.10.4); any other env var is dropped.
  • Cache dir: <workspace>/../.ci-cache/eslint/<lockfile hash>, beside the checkout. Persistent self-hosted runner:
    the directory is the cache, no save/restore. GitHub-hosted: actions/cache/restore everywhere, save only on the
    default branch, both guarded runner.environment == 'github-hosted' (R8). A new lockfile is a cold cache.
  • The cache path is absolute. actions/cache/save rejects any pattern containing ..
    (Relative pathing '.' and '..' is not allowed), so the dependency cache's ../.ci-cache/... form cannot be copied.
  • Scope is Fast only (fast and fast-escalable; they share one step list). Build, Checks, Extra gate and
    the escalated Fast lint cold: ESLint's cache keys on a file's own content and config and does not see a type
    change in another file, so a type-aware rule (@typescript-eslint/no-floating-promises, in narduk-libs' server
    pack) can pass a cached, unchanged file that a changed file just broke. The cold full gate is the net.
    eslint-cache: false turns it off for Fast too.
  • Not covered: narduk-lint (narduk-libs lint-budget wrapper) takes --cache but no --cache-strategy, so the
    content strategy cannot be injected there.

Task 1 (not changed, with proof): static Fast names. The brief's preferred fix does not work on GitHub.
Probed on a skipped job inside a reusable workflow (run 36654444065 and 36654519725): a skipped job's name is its
literal template whatever contexts the expression reads. inputs.*, github.*, vars.* and needs.* names all
render raw, and text mixed with an expression keeps its ${{ ... }}. Only a static name renders cleanly, and a
static Fast on a skipped job is a skipped check, which passes the org ruleset tier-t1-ci-fast (required context
ci / Fast): exactly the false green the current design prevents. So the three names are unchanged, and the comment
at NAMING IS THE GATE and the README now record the probe. Getting clean names needs a decision outside this file:
an always-running job named Fast (a runner seat per run) or a ruleset that requires a differently named context.

Proof

  • actionlint -no-color .github/workflows/*.yml: clean. scripts/lint_callables.py: 0 findings.
  • New scripts/test_eslint_cache.py (in ci.yml): executes the shipped step and preload against a stub eslint bin
    and asserts the wiring. Also run: test_fast_path.py, test_e2e_reuse.py, test_cache_paths.py,
    test_store_placement.py, test_required_gate.py, test_permission_ceiling.py: all pass.
  • Live (temporary fixture caller on this branch, removed before this commit; hosted, public repo): a 400-file
    eslint 9.39.4 fixture whose lint script is a node wrapper that runs pnpm exec eslint src.
    Run 36657596231 (cold): flag injected through the wrapper, 400 misses, Cache saved.
    Run 36657695538 (next commit): Cache restored from key eslint-cache-v1-..., 0 misses, 400 stores.
    The fixture is too small for a meaningful timing (about 1.6 s cold vs 1.0 s warm); real numbers come from the
    first app re-pin. The temporary probe allowed the save on the branch; the default-branch rule is unit-asserted.

Not done / risks

  • Self-hosted persistence is by design, not observed here: this repo is public and its runs are hosted.
    ../.ci-cache is under the per-listener _work on the transient volume, so a hit needs the same listener.
  • Separate finding, not fixed here: the hosted Save dependency cache uses the same relative ../.ci-cache/...
    path that actions/cache/save rejected in this probe, so it may never have saved since fix(ci): keep the hosted dependency store beside the checkout #174.

🤖 Generated with Claude Code

… skipped Fast name cannot be prettied

Fast lint ran cold every time. A preload (NODE_OPTIONS --require, set for
the Run fast scripts step only) appends --cache --cache-strategy content to
any eslint CLI process the caller's fast-scripts start, however deep in
pnpm --filter / turbo / a wrapper. Cache dir is beside the checkout, keyed
by lockfile hash: persistent on self-hosted, restored everywhere and saved
on the default branch only on GitHub-hosted. New input eslint-cache
(default true). Fast lanes only: the full gate stays cold because a content
cache cannot see cross-file type changes.

Task 1 finding: a skipped job's name is not evaluated whatever contexts it
reads (probed), and a static Fast would be a passing ci / Fast, so the
names are unchanged; the comment at NAMING IS THE GATE records the probe.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@loganrenz loganrenz added the enhancement New feature or request label Sep 30, 2026
@loganrenz
loganrenz enabled auto-merge (squash) September 30, 2026 02:02
@loganrenz
loganrenz merged commit 9767b94 into main Sep 30, 2026
3 checks passed
@loganrenz
loganrenz deleted the eslint-cache-names branch September 30, 2026 02:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant