A guard for the failures that only happen on the platform
Two things had taken production down and neither could fail locally: an extensionless import that a bundler hides and Node refuses, and a vercel.json pattern that produces no deployment at all. Both are now checked before the build, and the guard was proved by reintroducing each bug.
Types pass, the bundler builds, the dev server serves — and the deployment answers 500 on every request. That gap is what this script is for. All three of those tools resolve modules and read configuration the way a bundler does; the deployed function does neither, and the script checks exactly the difference. It runs inside npm run build and exits non-zero, so neither mistake can reach a push again.
What it refuses
A relative import with no extension. The API runs as ESM on Node, where ./faq does not resolve and ./faq.js does. One such line, reached from the server's own import graph, answered every /api route with FUNCTION_INVOCATION_FAILED.
A .json import in that graph. import { version } from '../package.json' type-checks, builds, and works in the dev server. The deployed bundle carries modules and not the repository, so the file is simply not there and the import throws at module load — which is every request, so the whole API returned 500.
A source pattern the platform's router will not parse. The symptom here is not a failing deploy: an invalid pattern is rejected before a build starts, so there is no deployment at all and production quietly stays on the commit before. The patterns are parsed with the same library the platform parses them with.
A version that disagrees with itself. shared/version.ts must equal package.json. It is a copy precisely because a JSON import is the failure above, and a copy nobody checks goes stale; the extension's manifest and the release tag read one of them, the connector reads the other.
How it decides what to look at
The rule applies to the files the deployed function actually loads, and that set is not "everything under server/" — it follows imports wherever they lead, which is how a file under src/lib became part of the server in the first place. So it starts at the function's entry point and walks. A type-only import is skipped: it is erased at compile time, so its specifier never becomes something a runtime has to resolve.
What it is not
Not a test suite and not a linter. It knows four specific ways the platform differs from a laptop and nothing else; it will not notice a logic error, and it warns rather than fails if the library it parses patterns with is not installed, because the point is to catch the mistake on the machine where it is being made. Each rule was proved by putting its bug back and watching the check fail.
Related: documentation that lives in the repository, and publishing Markdown from GitHub Actions.