a desktop audit was not a desktop audit

`formFactor: 'desktop'` changes which thresholds a metric is scored against and
NOTHING else. Throttling and the user agent keep their defaults, which are mobile
— so every desktop run was a desktop-sized window on a 4x-slowed CPU over slow 4G,
announced as a moto-g.

It read 86 where the same page reads 100. That gap was reported repeatedly as
network latency to the host. It was not latency; it was this. Measured after the
fix: desktop 100, LCP 0.4s against 2.2s.

Nine more from the same review:

  runtimeError was never checked, so a page that failed to load reported
  "nothing failing" — the most reassuring possible output for a site that is down

  --json exited 0 before the gate, so the documented non-zero exit was true for a
  person reading the table and false for the only caller that could act on it

  scoreDisplayMode 'error' was filtered out while still nulling its category, so
  a category could read 0 with an empty findings list

  a missing metric serialised as 0, which a script reads as a perfect measurement

  `source` is a string on some audits and an object on others; String() on the
  object printed [object Object]

  the watchdog's surrender was permanent — the health branch sat below the check,
  so once it stopped trying it also stopped noticing, and a server fixed by hand
  left it asleep until the platform restarted

  a failed restart leaves no process at all, because startServer deletes before
  it starts. status null then reads as "somebody stopped it", which the watchdog
  leaves alone — one bad restart would have turned it off and taken the server
  with it, silently

  the skill claimed the panel uses this engine. Nothing but the CLI does

  and gave `bun run build:site` with no cwd, which only works from the website
  checkout — api/static-site.ts documents that and the skill did not

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-05 18:42:45 +01:00
co-authored by Claude Opus 5
parent 05ad4f4d51
commit 74c6776c75
4 changed files with 147 additions and 27 deletions
+21 -4
View File
@@ -32,9 +32,20 @@ const factors: FormFactor[] = args.includes('--mobile')
? ['desktop']
: ['mobile', 'desktop'];
/** Lighthouse's own bands, so a number reads as good or not without looking them up. */
/**
* Lighthouse's own bands, so a number reads as good or not without looking them up.
*
* `✓` is 90 and up, which is what Lighthouse calls green — NOT the same as the exit gate below, which
* is 100. The two disagreeing is deliberate and worth saying out loud: green is Lighthouse's word for
* good, and this tool's exit code answers a different question, which is whether there is anything
* left to do.
*/
const band = (score: number | null) => (score === null ? ' ? ' : score >= 90 ? ' ✓ ' : score >= 50 ? ' ~ ' : ' ✗ ');
/** Every category on every form factor at 100 — see the note on `band`. */
const perfect = (results: { scores: Record<string, number | null> }[]) =>
results.every((one) => Object.values(one.scores).every((score) => score === 100));
const results = [];
for (const formFactor of factors) {
// To stderr, so `--json` on stdout stays a clean pipe while the wait is still narrated.
@@ -43,7 +54,14 @@ for (const formFactor of factors) {
if (json) {
console.log(JSON.stringify(results, null, 2));
process.exit(0);
/*
The same gate as below, not `exit(0)`.
`--json` is the mode a script uses, and a script is exactly the caller that reads an exit code.
Exiting 0 here meant the documented "non-zero when anything is short of 100" was true for a person
watching the table and false for the only consumer that could act on it.
*/
process.exit(perfect(results) ? 0 : 1);
}
for (const result of results) {
@@ -74,5 +92,4 @@ for (const result of results) {
}
// A non-zero exit when anything is short of 100, so this can gate a build without being parsed.
const perfect = results.every((one) => Object.values(one.scores).every((score) => score === 100));
process.exit(perfect ? 0 : 1);
process.exit(perfect(results) ? 0 : 1);