{"record":{"id":"bbb411edbcd68200","repo":"santifer/career-ops","slug":"node-sqlite-unavailable-node-22-5-tracker-index-tests","errorCode":null,"errorMessage":"node:sqlite unavailable (Node < 22.5) — tracker index tests skipped","messagePattern":"node:sqlite unavailable \\(Node < 22\\.5\\) — tracker index tests skipped","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"test-all.mjs","lineNumber":13119,"sourceCode":"  } else {\n    fail('AGENTS.md misses onboarding state docs or CLAUDE.md is not a thin wrapper');\n  }\n} catch (e) {\n  fail(`Cold-start trigger test crashed: ${e.message}`);\n}\n\n// ── 15. TRACKER DERIVED INDEX (#918 phase 1) ────────────────────\n// applications.md is the source of truth; applications.db is a derived index\n// rebuilt from it. Round-trip md → db → md must be lossless for clean input\n// (a hard condition from #918 before any phase-2 work), sync must DETECT\n// corruption without ever modifying the markdown, and reads must never be\n// stale.\n\nconsole.log('\\n15. Tracker derived index (sync/query/export round-trip)');\n\nconst sqliteAvailable = run(NODE, ['--no-warnings', '-e', \"import('node:sqlite').then(()=>process.exit(0),()=>process.exit(1))\"]) !== null;\nif (!sqliteAvailable) {\n  warn('node:sqlite unavailable (Node < 22.5) — tracker index tests skipped');\n} else {\n  try {\n    const idxTmp = mkdtempSync(join(tmpdir(), 'career-ops-index-'));\n    try {\n      const md = join(idxTmp, 'applications.md');\n      const env = { ...process.env, CAREER_OPS_TRACKER: md };\n      const trackerRun = (args) => run(NODE, ['tracker.mjs', ...args], { env, stdio: ['pipe', 'pipe', 'pipe'] });\n\n      // 1. Round trip: clean canonical input must export byte-identical.\n      const clean =\n        '# Applications Tracker\\n\\n' +\n        '| # | Date | Company | Role | Score | Status | PDF | Report | Notes |\\n' +\n        '|---|------|---------|------|-------|--------|-----|--------|-------|\\n' +\n        '| 2 | 2026-01-05 | Beta | Designer | 4.0/5 | Applied | ✅ | [2](../reports/002-beta-2026-01-05.md) | second |\\n' +\n        '| 1 | 2026-01-04 | Acme | Engineer | 4.2/5 | Evaluated | ❌ | [1](../reports/001-acme-2026-01-04.md) | first |\\n';\n      writeFileSync(md, clean);\n      if (trackerRun(['sync']) === null) {\n        fail('tracker sync crashed on clean fixture');","sourceCodeStart":13101,"sourceCodeEnd":13137,"githubUrl":"https://github.com/santifer/career-ops/blob/e7abd431fce9348a95261acac9e0c14779c35df8/test-all.mjs#L13101-L13137","documentation":"Section 15 of test-all.mjs tests the tracker's derived SQLite index; it first probes `import('node:sqlite')` in a child Node process. node:sqlite is only available from Node 22.5+, so on older runtimes the probe exits non-zero and the test warns that tracker index tests are skipped rather than failing.","triggerScenarios":"`run(NODE, ['--no-warnings', '-e', \"import('node:sqlite').then(()=>process.exit(0),()=>process.exit(1))\"])` returns null because the active Node is < 22.5 (or a build without the sqlite module), making sqliteAvailable false.","commonSituations":"CI matrices pinned to Node 20 LTS, contributors with system Node 18/20, nvm pointing at an older default, or Docker images based on node:20.","solutions":["Upgrade Node to >= 22.5 (nvm install 22 && nvm use 22) so the index tests run.","Pin a modern Node in CI (actions/setup-node with node-version: '22').","Accept the skip on older Node — the tests are additive coverage, not a correctness gate for the rest of the suite.","If you need this test but cannot upgrade, run just section 15 under a Node 22+ binary by pointing NODE at it."],"exampleFix":"// before (CI)\n- uses: actions/setup-node@v4\n  with: { node-version: '20' }\n// after\n  with: { node-version: '22' }","handlingStrategy":"fallback","validationCode":"let sqliteOk = false; try { await import('node:sqlite'); sqliteOk = true; } catch {} if (!sqliteOk) console.warn('Node >= 22.5 required for tracker index tests');","typeGuard":"const supportsNodeSqlite = (v) => { const [maj, min] = v.split('.').map(Number); return maj > 22 || (maj === 22 && min >= 5); };","tryCatchPattern":"const available = run(NODE, ['--no-warnings', '-e', \"import('node:sqlite').then(()=>process.exit(0),()=>process.exit(1))\"]) !== null; if (!available) warn('node:sqlite unavailable — skipping index tests');","preventionTips":["Use Node >= 22.5 for full test coverage (nvm install 22)","Pin node-version: 22 in CI matrices","Gate sqlite-dependent features on a runtime capability probe, not a version string","Document the minimum Node version in the README"],"tags":["node-sqlite","node-version","environment","test-runner"],"backgroundTag":"missing-dependency","analyzedSha":"e7abd431fce9348a95261acac9e0c14779c35df8","analyzedAt":"2026-09-16T06:35:29.214Z","contentChangedAt":"2026-09-16T06:35:29.214Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}