node-js-e2e-battery-criterion-mislabel
Root cause. The app loads sql.js the standard CDN way — the sql-wasm.js loader script defines initSqlJs on window (a top-level var that lands on the global in a classic <script>), and the app calls it to obtain the SQL module. The symbol sqlJs does not exist anywhere: not in the vendor artifact, not in the app. Battery test T93's 'sqlJs': 'function' criterion was a mislabel carried forward from an earlier version, so it failed against every healthy build — a false FAIL with no app defect.
The fix is a one-line criterion change, not an app change.
// battery/t93.js — BEFORE (mislabel carried forward): asserts a global the app never defines
module.exports = {
id: 'T93',
target: 'window.sqlJs',
expect: 'function', // false FAIL on every healthy build
};
// battery/t93.js — AFTER (fixed): assert the loader symbol the app actually loads
module.exports = {
id: 'T93',
target: 'window.initSqlJs', // sql.js CDN loader (sql-wasm.js) exports initSqlJs
expect: 'function', // PASS — zero app code changes
};
If the battery engine evaluates criteria like typeof window[target] === expect, the fix is literally the target string swap above. A belt-and-braces variant that also covers the post-init contract (only if the battery can poll asynchronously — SQL is populated only after the initSqlJs() promise resolves, so a synchronous page-load check must use the loader symbol):
const crit = [
{ target: 'window.initSqlJs', expect: 'function' }, // loader present (sync, always assertable)
{ target: 'window.SQL', expect: 'object' }, // module exposed after async init (poll)
];
Generalized fix procedure (the lesson, codified):
1. Read the app's loader code and note the real symbol: const SQL = await initSqlJs({ locateFile }) → the loader symbol is initSqlJs, the exposed module is SQL.
2. Verify against the vendor artifact, don't guess: grep -c 'sqlJs' sql-wasm.js → 0; grep -o 'initSqlJs' sql-wasm.js | wc -l → 11.
3. Fix the criterion to the verified symbol; re-run the battery.
4. Only if the corrected criterion still fails (or the app's initSqlJs/SQL globals are genuinely absent at runtime) treat it as a regression.
Verified against the **real CDN artifacts** (`sql.js@1.10.3` `sql-wasm.js` + `sql-wasm.wasm`, downloaded from cdnjs) in `/tmp/sqljs-check/verify.js` — a browser-faithful `vm` sandbox where `window === globalThis` and the loader is evaluated as a top-level script (true `<script>` semantics), plus a node-path load of the same artifact. 14/14 checks pass: | # | Check | Result | |---|-------|--------| | 1 | Real artifact defines `window.initSqlJs` as function | PASS | | 2 | Real artifact never defines `window.sqlJs` (`typeof === 'undefined'`) | PASS | | 3 | T93 **old** criterion `sqlJs: function` → **false FAIL** (the bug reproduced) | PASS | | 4 | T93 **fixed** criterion `initSqlJs: function` → **PASS, zero app changes** | PASS | | 5 | Full sandbox browser boot: `initSqlJs()` resolves, `window.SQL` populated | PASS | | 6 | End-to-end SQLite: `CREATE TABLE` → `INSERT` → `SELECT` returns `[1,"sql.js"]` | PASS | | 7 | Edge: loader 404 → fixed criterion **still fails** (fix does not mask real regressions) | PASS | | 8 | Edge: init pending → `initSqlJs` already assertable | PASS | | 9 | Edge: init pending → `SQL` not yet available (why the loader symbol is the right sync assert) | PASS | | 10–13 | Edge: typo variants `sqljs`, `SqlJs`, `initSqlJS`, `Sqljs` correctly fail | PASS | | 14 | Edge: `initSqlJs` idempotent (2nd call returns cached module) | PASS | Key edge cases covered: **no masking** (a genuinely missing loader still FAILs the corrected criterion — the fix only kills false negatives, not real ones); **async timing** (loader symbol is synchronously assertable, `SQL` is not — asserting `SQL` at page load would reintroduce a false FAIL); **case/typo sensitivity** (only the exact real symbol passes); **vendor-ground-truth** (verified against the actual shipped artifact, not docs). ``` [PASS] artifact defines initSqlJs on window (typeof window.initSqlJs === 'function') [PASS] artifact never defines sqlJs (typeof window.sqlJs === 'undefined') [PASS] T93 OLD criterion (sqlJs: function) -> false FAIL (the bug) [PASS] T93 FIXED criterion (initSqlJs: function) -> PASS, no app changes ... totals: 14 passed, 0 failed ```
{"model": "deepseek-v4-flash", "problem_class": "node-js-e2e-battery-criterion-mislabel", "result": "passed", "tests": 14}