TL;DR
The CI runner is on a different Node version than your machine because the lockfile drifted from what CI actually installs. Pin one Node version in CI config and commit the lockfile, then the mismatch disappears.

```text
the agent assumed CI and local used the same Node version  -  the lockfile had drifted
```

## Steps
1. Print both versions. Run `node -v` locally, then find the same line in a recent CI log. If they differ, that is the bug.
   Expected: you see two different version numbers, e.g. local v22.4.0 vs CI v20.18.0.
2. Check what the lockfile says. Look for an `engines` field or a Volta/pnpm `node` pin inside package-lock.json or pnpm-lock.yaml, and compare it with the `node-version` in the CI workflow file.
   Expected: you find the lockfile asks for one version while the workflow asks for another (or for nothing, which means "latest", which drifts).
3. Pin the version in one place CI trusts. Add the exact version to the workflow's setup step (most teams use a `.nvmrc` file or the `node-version-file` option) so every run uses the same one.
   Expected: the next CI run logs the pinned version in its setup output.
4. Reinstall and commit the lockfile. Delete node_modules, install fresh with the pinned version, and commit the updated lockfile so local and CI resolve the same dependency tree.
   Expected: a fresh clone plus the pinned version reproduces CI exactly.
5. Rerun the failing test in CI.
   Expected: green on the same code that failed before, with no test changes.

## Use this when
- a test passes locally but fails in CI with no code change between the two
- the agent assumed the environments matched and never checked the Node version
- dependency behavior differs between runs (native modules, optional deps)
- `engines` in package.json disagrees with the CI workflow

## Not for this skill when
- the failure reproduces identically on local and CI (version is not the cause)
- only one environment exists or matters
- the problem is a package version mismatch, not a Node runtime mismatch
- you are debugging a single environment's setup, not a divergence between two

## Variant phrasings
- "works on my machine but fails in github actions with a different node version"
- "CI installs different dependencies than local because the lockfile was not committed"
- "lockfile drift between local and CI causing test failures"

## Why it happens
CI usually resolves the Node version from the workflow file, not from your lockfile or your laptop. If the workflow says nothing (or says "latest") and the lockfile was generated or hand-edited on a different Node version, the two sides install different trees. Some packages ship different native binaries per Node major version, so a test can pass on one side and explode on the other with no code change at all.

## Edge cases
- The workflow may install Node from a container image tag, not a setup action; pin the image tag too.
- `npm ci` ignores a drifted package.json but still runs on whatever Node the runner has; the lockfile alone does not pin the runtime.
- A developer's globally installed Node can mask the problem locally; always check the project's pinned version, not `node -v` on PATH.
- Monorepos sometimes pin Node per package; check every workspace that the failing test touches.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_Vp9GMO9YKdUqRpzs0pYf9w
