ข้ามไปยังเนื้อหา

บันไดเครื่องมือตรวจสอบ

AI bug catalog ระบุเครื่องมือไว้สำหรับแต่ละ 24 pattern — ส่วนใหญ่คือ “ไม่มี — ต้องใช้คนเท่านั้น” บทนี้รันเครื่องมือทุกตัวที่ มีจริง ให้ดูจริง กับโค้ด Node.js จริง และยกผลลัพธ์ที่ได้มาตรง ๆ: ไม่มีการแต่งผลลัพธ์ ไม่มีชื่อกฎที่คิดขึ้นเอง ไม่มีเครื่องมือไหนใน repo นี้เลย — แต่ละตัวถูกติดตั้งในโปรเจกต์ scratch แบบใช้แล้วทิ้ง (npm install --save-dev สำหรับ npm package, brew install osv-scanner สำหรับตัวที่ไม่ใช่) แล้วรันที่นั่น เหมือนกับที่ reviewer จะติดตั้งให้โปรเจกต์ที่ยังไม่มีเครื่องมือนี้จริง ๆ

test runner ในตัวไม่ต้องติดตั้งอะไรเลย เมื่อมี math.cjs ที่ export add กับ subtract และไฟล์ test ที่ใช้แค่ add

// @skip-verify illustrative -- ./math.cjs is a separate file, shown only to name the setup
const test = require('node:test');
const assert = require('node:assert/strict');
const { add } = require('./math.cjs');
test('adds two numbers', function () {
assert.equal(add(2, 3), 5);
});
Node.js
Output (verified on Node 24)
assertion passed

รันจริงด้วย node --test --experimental-test-coverage:

✔ adds two numbers (0.5ms)
ℹ tests 1
ℹ suites 0
ℹ pass 1
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 58.8
ℹ start of coverage report
ℹ ----------------------------------------------------------
ℹ file | line % | branch % | funcs % | uncovered lines
ℹ ----------------------------------------------------------
ℹ math.cjs | 66.67 | 100.00 | 50.00 | 5-7
ℹ ----------------------------------------------------------
ℹ all files | 66.67 | 100.00 | 50.00 |
ℹ ----------------------------------------------------------
ℹ end of coverage report

(เวลาต่อ test ต่างกันไปในแต่ละครั้งที่รัน แต่ตัวเลข coverage ไม่ต่างกัน) subtract ไม่เคยถูกเรียกจากไฟล์ test เลย และรายงาน coverage ก็บอกตรง ๆ: line coverage 66.67% บรรทัดของ subtract ถูกระบุเป็น uncovered --experimental-test-coverage ยังเป็น flag แบบ experimental บน Node 24.13 — เสถียรพอที่จะพึ่งพาได้ แต่ยังไม่เสถียรพอที่รูปแบบรายงานที่แน่นอนของมันจะไม่เปลี่ยนในเวอร์ชันถัดไป

--trace-warnings เปลี่ยน warning เปล่า ๆ ให้กลายเป็น stack trace เต็มที่ชี้ไปยังจุดที่ปัญหาถูกสร้างขึ้นจริง รันกับ pattern listener leak จาก AI bug catalog:

listener count: 11
(node:45399) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 data listeners added to [EventEmitter]. MaxListeners is 10. Use emitter.setMaxListeners() to increase limit
at genericNodeError (node:internal/errors:985:15)
at wrappedFn (node:internal/errors:539:14)
at _addListener (node:events:582:17)
at EventEmitter.addListener (node:events:600:10)
at handleRequest (file:///.../listener-leak.mjs:10:11)
at file:///.../listener-leak.mjs:13:30
warning name: MaxListenersExceededWarning

ถ้าไม่มี flag นี้ warning ก็ยัง print อยู่ — แค่ไม่มี stack เหลือแค่ “listener นี้ถูกเพิ่มที่ไหนจริง ๆ” เป็นการค้นหาด้วยมือทั่วทั้ง codebase แทนที่จะเป็นเลขบรรทัดที่ชัดเจน

--unhandled-rejections=strict เป็นพฤติกรรม ดีฟอลต์ มาตั้งแต่ Node 15 — รันแบบระบุ flag ตรง ๆ กับ pattern floating promise ให้ผล crash เดียวกันไม่ว่าจะมี flag หรือไม่:

save queued
Error: missing id
at saveRecord (...)
Node.js v24.13.0

flag นี้มีความหมายสำหรับโค้ดที่ยังรันบน Node เวอร์ชันเก่ามาก ๆ หรือ codebase ที่จงใจ override ค่าดีฟอลต์กลับไปเป็น warn — บน Node 24.13 ปัจจุบัน การ crash เกิดขึ้นเหมือนกันไม่ว่าจะมี flag หรือไม่

--trace-uncaught เพิ่มอีกหนึ่งส่วน Thrown at: เข้าไปบน output ดีฟอลต์ของ uncaught exception ใน Node — ชี้ไปยังบรรทัดที่ error ถูก throw จริง แยกจากจุดที่มันถูก catch (หรือไม่ถูก catch) ขึ้นไปใน stack กับ pattern event error ที่ไม่มี listener output ดีฟอลต์ก็แสดง Emitted 'error' event at: อยู่แล้ว --trace-uncaught เพิ่ม block Thrown at: ที่สองเข้ามาด้วยตำแหน่งเดียวกันสำหรับกรณีง่าย ๆ นี้ แต่ทั้งสองอาจต่างกันได้ในโค้ดที่ error ถูก throw ที่หนึ่งแล้วโผล่ขึ้นไปถึง top level ที่อีกจุดหนึ่งไปเลย

ติดตั้งในโปรเจกต์ scratch: [email protected], [email protected], [email protected] flat config โดยใช้ flat preset ที่แต่ละ plugin export มาเอง:

// @skip-verify eslint config, not a runnable program
import n from 'eslint-plugin-n';
import promise from 'eslint-plugin-promise';
export default [
n.configs['flat/recommended-module'],
promise.configs['flat/recommended'],
{
rules: {
'no-eval': 'error',
},
},
];

รันกับไฟล์เป้าหมายที่สร้างขึ้นเพื่อรวม pattern จาก AI bug catalog หลายตัวไว้ด้วยกัน:

// @expect-throw
import fs from 'node:fs';
const data = fs.readFileSync('/etc/hosts');
function fetchUser(id) {
return new Promise(function (ok, bad) {
ok({ id: id });
});
}
function handleUser(id) {
fetchUser(id).then(function (user) {
console.log(user);
});
}
function chained(id) {
return fetchUser(id).then(function (user) {
fetchUser(user.id + 1).then(function (next) {
console.log(next);
});
});
}
handleUser(1);
chained(2);
eval('console.log(1)');
process.exit(1);
new Buffer(10);

npx eslint bad-file.mjs ผลลัพธ์จริง:

6:32 error Promise constructor parameters must be named to match "^_?resolve$" promise/param-names
6:36 error Promise constructor parameters must be named to match "^_?reject$" promise/param-names
12:3 error Expected catch() or return promise/catch-or-return
12:22 error Each then() should return a value or throw promise/always-return
18:29 error Each then() should return a value or throw promise/always-return
19:5 error Expected catch() or return promise/catch-or-return
19:28 warning Avoid nesting promises promise/no-nesting
19:33 error Each then() should return a value or throw promise/always-return
28:1 error eval can be harmful no-eval
30:1 error Don't use process.exit(); throw an error instead n/no-process-exit
32:1 error 'new Buffer()' was deprecated since v6.0.0. Use 'Buffer.alloc()' or 'Buffer.from()' instead n/no-deprecated-api
✖ 11 problems (10 errors, 1 warning)

เจ็ดกฎที่ต่างกันทำงานบนไฟล์เดียว: promise/param-names, promise/catch-or-return, promise/always-return, promise/no-nesting, no-eval, n/no-process-exit, n/no-deprecated-api สังเกตสิ่งที่ ไม่ ทำงาน: fs.readFileSync บรรทัด 3 (pattern 6, งาน synchronous ใน hot path) ไม่มีกฎใดจับมันเลย — การอ่านว่ามันเสี่ยงต้องรู้ว่ามันรันข้างใน request handler ซึ่งเป็นบริบทที่ linter ที่มองไฟล์เดียวไม่มีทางรู้ได้

กับโปรเจกต์ scratch ที่ pin ไว้ที่ [email protected] (npm audit ผลลัพธ์จริง):

# npm audit report
lodash <=4.17.23
Severity: critical
Prototype Pollution in lodash - https://github.com/advisories/GHSA-fvqr-27wr-82fm
Command Injection in lodash - https://github.com/advisories/GHSA-35jh-r3h4-6jhm
Prototype Pollution in lodash - https://github.com/advisories/GHSA-4xc9-xhrj-v574
Prototype Pollution in lodash - https://github.com/advisories/GHSA-jf85-cpcp-j695
Prototype Pollution in lodash - https://github.com/advisories/GHSA-p6mc-m468-83gw
Regular Expression Denial of Service (ReDoS) in lodash - https://github.com/advisories/GHSA-29mw-wpgm-hmr9
Regular Expression Denial of Service (ReDoS) in lodash - https://github.com/advisories/GHSA-x5rq-j2xg-h7qm
lodash vulnerable to Code Injection via `_.template` imports key names - https://github.com/advisories/GHSA-r5fr-rjxr-66jc
lodash vulnerable to Prototype Pollution via array path bypass in `_.unset` and `_.omit` - https://github.com/advisories/GHSA-f23m-r3pf-42rh
Lodash has Prototype Pollution Vulnerability in `_.unset` and `_.omit` functions - https://github.com/advisories/GHSA-xxjr-mmjv-4gpg
fix available via `npm audit fix --force`
Will install [email protected], which is outside the stated dependency range
node_modules/lodash
1 critical severity vulnerability

package-lock.json ตัวเดียวกัน osv-scanner scan source -L package-lock.json (osv-scanner 2.6.0 ติดตั้งด้วย brew install osv-scanner):

Total 1 package affected by 8 known vulnerabilities (1 Critical, 2 High, 4 Medium, 0 Low, 1 Unknown) from 1 ecosystem.
8 vulnerabilities can be fixed.
+-------------------------------------+------+-----------+---------+---------+---------------+
| OSV URL | CVSS | ECOSYSTEM | PACKAGE | VERSION | FIXED VERSION |
+-------------------------------------+------+-----------+---------+---------+---------------+
| https://osv.dev/GHSA-29mw-wpgm-hmr9 | 5.3 | npm | lodash | 4.17.4 | 4.17.21 |
| https://osv.dev/GHSA-35jh-r3h4-6jhm | 8.1 | npm | lodash | 4.17.4 | 4.17.21 |
| https://osv.dev/GHSA-4xc9-xhrj-v574 | | npm | lodash | 4.17.4 | 4.17.11 |
| https://osv.dev/GHSA-f23m-r3pf-42rh | 6.9 | npm | lodash | 4.17.4 | 4.18.0 |
| https://osv.dev/GHSA-fvqr-27wr-82fm | 6.5 | npm | lodash | 4.17.4 | 4.17.5 |
| https://osv.dev/GHSA-jf85-cpcp-j695 | 9.1 | npm | lodash | 4.17.4 | 4.17.12 |
| https://osv.dev/GHSA-p6mc-m468-83gw | 7.4 | npm | lodash | 4.17.4 | 4.17.19 |
| https://osv.dev/GHSA-x5rq-j2xg-h7qm | 6.5 | npm | lodash | 4.17.4 | 4.17.11 |
+-------------------------------------+------+-----------+---------+---------+---------------+

ทั้งสองเครื่องมือพบ advisory พื้นฐานเดียวกันจาก lockfile เดียวกัน; osv-scanner เพิ่มเติมด้วยคะแนน CVSS และเวอร์ชันที่แก้แล้วเฉพาะของแต่ละ advisory และอ่านฐานข้อมูล OSV โดยตรงแทนที่จะเป็น advisory feed ของ npm เอง ไม่มีเครื่องมือไหนเกี่ยวข้องกับ pattern 24 ของแคตตาล็อก (exec/eval injection ใน โค้ดของคุณเอง) เลย — ทั้งคู่รู้แค่เรื่องช่องโหว่ใน package ที่คุณ depend ไว้ ไม่ใช่ bug ที่คุณเขียนเอง

กับ server ตัวจริงจากบท Production Server ที่ listen บนพอร์ตจริง autocannon -c 10 -d 4 บน /health:

┌─────────┬──────┬──────┬───────┬──────┬─────────┬─────────┬──────┐
│ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │
├─────────┼──────┼──────┼───────┼──────┼─────────┼─────────┼──────┤
│ Latency │ 0 ms │ 0 ms │ 0 ms │ 0 ms │ 0.01 ms │ 0.05 ms │ 6 ms │
└─────────┴──────┴──────┴───────┴──────┴─────────┴─────────┴──────┘
┌───────────┬─────────┬─────────┬─────────┬─────────┬───────────┬──────────┬─────────┐
│ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │
├───────────┼─────────┼─────────┼─────────┼─────────┼───────────┼──────────┼─────────┤
│ Req/Sec │ 60,479 │ 60,479 │ 67,007 │ 71,487 │ 67,572 │ 4,487.68 │ 60,456 │
└───────────┴─────────┴─────────┴─────────┴─────────┴───────────┴──────────┴─────────┘
270k requests in 4.01s, 58.7 MB read

จัดเป็น bucket เพื่อให้ reproduce ได้ (ตัวเลขแน่นอนเปลี่ยนไปในแต่ละครั้งที่รัน แต่ bucket ไม่เปลี่ยน): latency ต่ำกว่ามิลลิวินาที ประมาณ 60k–75k requests/second บนเครื่องนี้สำหรับ handler ที่ไม่มีงานจริงเลยนอกจาก JSON.stringify การรัน load เดียวกันด้วย node --cpu-prof --cpu-prof-dir=. --cpu-prof-name=prod.cpuprofile server.cjs สร้างไฟล์ .cpuprofile จริง (โหลดใน panel Performance ของ Chrome DevTools ได้ หรือตรวจสอบเป็น JSON ตรง ๆ ก็ได้); รวม hit count ตามชื่อฟังก์ชันจาก profile จริงของการรันนี้:

(idle) 1899
writev 973
(program) 229
writevGeneric 59
finish 53
_storeHeader 45
nextTick 44
(garbage collector) 41

(idle) ครองอันดับหนึ่ง — ตามคาดสำหรับ handler แบบ health-check ที่ไม่มีงาน CPU-bound เลย — และ frame ที่ร้อนรองลงมาล้วนอยู่ใน path การเขียน HTTP ของ Node เอง (writev, writevGeneric, _storeHeader, finish) ไม่ใช่โค้ดแอปพลิเคชัน นี่คือลายเซ็นที่จะ ต่างออกไป สำหรับ pattern 6 (งาน CPU แบบ synchronous ใน handler) โดยตรง: busy-loop หรือ JSON.parse ขนาดใหญ่จะโผล่มาเป็น frame แอปพลิเคชันที่ร้อนและมีชื่อ แทนที่จะหายไปใน (idle) และ internal ของการเขียน socket

กับ package scratch สองไฟล์ที่ math.js export add, subtract, และ multiply แต่มีแค่ add เท่านั้นที่ถูก import ใช้จริง:

Unused exports (2)
subtract function src/math.js:5:17
multiply function src/math.js:9:17

knip หาสิ่งนี้ได้จากการตาม import graph จริง ไม่ใช่การจับคู่ข้อความ — เป็นเครื่องมือตัวเดียวใน ladder นี้ที่ตอบคำถามที่ 24 pattern ในแคตตาล็อกไม่ได้พูดถึงจริง ๆ (“โค้ดนี้ถูกเรียกถึงได้หรือไม่”) แทนที่จะเป็น “โค้ดที่ถูกเรียกถึงได้นี้ถูกต้องหรือไม่”

#Patternขั้นที่จับได้
1ลืม awaitไม่มี — ต้องใช้คนเท่านั้น
2forEach(async ...)ไม่มี — ต้องใช้คนเท่านั้น
3Floating promise / unhandled rejectionpromise/catch-or-return ของ eslint-plugin-promise; ตัว crash เป็นดีฟอลต์ของ Node เอง
4Promise.all ไม่จำกัด concurrencyไม่มี — ต้องใช้คนเท่านั้น (เปิดเผยได้ด้วย autocannon/load จริง)
5setTimeout(fn, 0) เทียบกับ setImmediate/nextTickไม่มี — ต้องใช้คนเท่านั้น
6งาน CPU แบบ synchronous ใน handlerไม่มี — ต้องใช้คนเท่านั้น (เปิดเผยได้ด้วย --cpu-prof/monitorEventLoopDelay)
7res.end() เรียกสองครั้งไม่มี — ต้องใช้คนเท่านั้น
8ตั้ง header หลังส่ง response แล้วไม่มี — ต้องใช้คนเท่านั้น
9ไม่จำกัดขนาด request bodyไม่มี — ต้องใช้คนเท่านั้น (เปิดเผยได้ด้วย autocannon)
10JSON.parse ไม่มี try/catchไม่มี — ต้องใช้คนเท่านั้น
11fetch ไม่เช็ก .ok/timeoutไม่มี — ต้องใช้คนเท่านั้น
12Listener leak--trace-warnings
13event error ไม่มี listenerไม่มี — ต้องใช้คนเท่านั้น
14.pipe() ไม่มีการจัดการ errorไม่มี — ต้องใช้คนเท่านั้น
15decode string ข้าม chunk boundaryไม่มี — ต้องใช้คนเท่านั้น
16Buffer.concat ข้างใน loopไม่มี — ต้องใช้คนเท่านั้น (เปิดเผยได้ด้วย --cpu-prof)
17process.env.PORT ถูกเทียบเป็น stringไม่มี — ต้องใช้คนเท่านั้น
18process.exit() กลางงานที่ยังค้างไม่มี — ต้องใช้คนเท่านั้น
19ปน require/import, __dirname ใน ESMไม่มี — ต้องใช้คนเท่านั้น (runtime error เกิดขึ้นทันที)
20^0.x, ไม่มี lockfile, npm install ใน Dockernpm audit/npm ci จับความคลาดเคลื่อนที่เกี่ยวข้องได้ ไม่ใช่ตัวเลือก Dockerfile เอง
21ลำดับ field exports ผิดไม่มี — ต้องใช้คนเท่านั้น
22ไม่มี assertion / mock ผิดที่ / test ใช้ timer จริงnode --test เมื่อมี assertion จริงและ mock ถูกใช้ในตำแหน่งที่ถูกต้อง
23console.log แทน structured logไม่มี — ต้องใช้คนเท่านั้น
24exec/eval injectionไม่มี — ต้องใช้คนเท่านั้น (npm audit/osv-scanner จับ dependency ที่มีช่องโหว่ ไม่ใช่สิ่งนี้)
Terminal window
node --test --experimental-test-coverage && \
NODE_OPTIONS="--trace-warnings --unhandled-rejections=strict" node --test && \
npx eslint . && \
npm audit --audit-level=high

สี่ขั้นในบรรทัด shell เดียว เชื่อมด้วย && ทำให้ล้มเหลวที่ขั้นไหนก็หยุดที่เหลือทันที — --cpu-prof/autocannon และ knip ถูกตั้งใจไม่รวมไว้ใน one-liner นี้ เพราะต้องมี server ที่รันอยู่จริงและ import graph เต็ม ๆ ตามลำดับ ไม่ใช่แค่ source tree ให้ lint และ test

ทุกขั้นใน ladder นี้ตอบคำถามที่แคบและเฉพาะเจาะจง — โค้ดทำตามที่ test บอกไหม มีอะไร warn ไหม style สม่ำเสมอไหม dependency มีช่องโหว่ที่รู้จักไหม เร็วพอไหม มีอะไรเรียกไม่ถึงไหม — และไม่มีข้อไหนตอบว่า “โค้ดนี้ถูกต้องหรือไม่” ตัวเลขในตาราง pattern-to-rung เองก็ยืนยันสิ่งนี้ชัดเจน: 21 จาก 24 pattern ในแคตตาล็อกไม่มีขั้นอัตโนมัติจับได้เลย

ทางเลือกประโยชน์ต้นทุน
รัน ladder เต็มทุก PRจับ bug กลุ่มจริงแม้จะแคบได้อัตโนมัติทุกครั้งหกเครื่องมือแยกกัน หลายตัวต้องการ network/CI setup (osv-scanner, autocannon ที่ต้องมี server รันอยู่จริง)
รันแค่ node --test + eslintเร็วพอสำหรับ pre-commit hookพลาด dependency ที่มีช่องโหว่, โค้ดที่เรียกไม่ถึง, และ performance regression ไปเลย
ถือว่า ladder รันสะอาดแล้วแปลว่า “รีวิวแล้ว”ไม่มี — นี่ไม่เคยเป็นข้อแลกเปลี่ยนที่ดีทุกเครื่องมือที่นี่แคบโดยการออกแบบ; run สะอาดพิสูจน์แค่ว่าสิ่งแคบ ๆ ที่มันเช็กนั้นโอเค
  • “--experimental-test-coverage เป็น experimental แปลว่าเชื่อถือไม่ได้” ชื่อ flag บอกว่ารูปแบบรายงานอาจยังเปลี่ยนได้ ไม่ได้บอกว่าตัวเลข coverage ที่มันแสดงวันนี้ผิด — มันมาจาก V8 coverage instrumentation จริง เป็น primitive เดียวกับที่เครื่องมือแบบ Istanbul สร้างต่อยอด
  • “npm audit กับ osv-scanner ซ้ำซ้อนกันเพราะเจอ advisory เดียวกันในตัวอย่างนี้” ทั้งคู่อ่านฐานข้อมูลต่างกัน (advisory feed ของ npm เองเทียบกับ aggregator ของ OSV) และอาจต่างกันได้ในระบบนิเวศที่ไม่ใช่ npm หรือ advisory ที่เพิ่งออกมาไม่นาน — รันตัวใดตัวหนึ่งไม่ใช่สิ่งทดแทนอีกตัวสำหรับทุกโปรเจกต์
  • “load test ด้วย autocannon พิสูจน์ว่า server ไม่มี bug” มันพิสูจน์แค่ว่า handler ตัวนี้ รับ concurrency นี้ และ payload รูปร่าง นี้ ไหวบนเครื่อง นี้ — ไม่ได้บอกอะไรเลยเกี่ยวกับ route อื่น, body ที่ใหญ่กว่า, หรือ handler ที่เป็น CPU-bound จริง ๆ

ก่อนจะเชื่อคำอ้างของ AI assistant ว่า “test ผ่านแล้ว” หรือ “lint สะอาดแล้ว” ให้ reproduce มันเอง: pattern 22 ของ AI bug catalog มีอยู่ก็เพราะ node --test ที่เขียวสามารถแปลว่า “ไม่มี assertion ที่เรียกถึงได้ตัวไหน fail” ไม่ใช่ “โค้ดนี้ถูกต้อง” รัน ladder จริงข้างบนกับ diff จริง อ่านชื่อกฎจริงใน output แล้วเช็กแต่ละจุดที่เจอกับตาราง pattern-to-rung ก่อนจะตัดสินว่าเครื่องมือ “จัดการ” เรื่องที่ตารางบอกว่ามันไม่ครอบคลุมแล้ว

🐛 หา bug ในโค้ดนี้

// PR description: "Added tests, lint is clean, ran npm audit -- all green."
function calculateDiscount(price, percent) {
return price - percent; // BUG: should be price - (price * percent / 100)
}
import { test } from 'node:test';
test('applies a discount', function () {
calculateDiscount(100, 10); // BUG: result never checked with an assertion
});
เฉลย

“lint สะอาด” กับ “npm audit เขียว” เป็นจริงทั้งคู่และไม่เกี่ยวข้องทั้งคู่: ไม่มีกฎ eslint ใน ladder ของคอร์สนี้เช็กเลขคณิต และ npm audit สแกนแค่ dependency ไม่ใช่ logic ของไฟล์นี้เอง ขั้นเดียวที่น่าจะจับ bug จริงได้ — node --test — ก็รายงานผ่านเช่นกัน เพราะ test ไม่เคย assert อะไรเกี่ยวกับค่าที่คืนกลับมาเลย ทั้งสามเครื่องมือรันจริงทั้งหมด และทั้งสามไม่ได้บอกอะไรเลยว่า calculateDiscount ถูกต้องหรือไม่ มีแค่การอ่าน body ของฟังก์ชันเทียบกับชื่อของมันเท่านั้นที่จับได้ว่า 100 - 10 ถูกคืนกลับมาแทนที่จะเป็น 100 - (100 * 10 / 100)

การรัน eslint ในบทนี้ยิงกฎที่ต่างกัน 7 ข้อบนไฟล์ 18 บรรทัด แต่ไม่พูดถึง fs.readFileSync('/etc/hosts') บนบรรทัดที่ 3 เลย ทำไมถึงเป็นแบบนั้น?
ทำไม npm audit และ osv-scanner ที่รันกับ lockfile เดียวกันซึ่งตรึง [email protected] ไว้ ถึงรายงานช่องโหว่ชุดเดียวกันแต่มีรายละเอียดบางอย่างต่างกัน?
ตามตาราง pattern-to-rung pattern ไหนใน AI bug catalog ที่เป็นข้อเดียวเท่านั้นที่ถูกกฎ eslint จับได้โดยตรง แทนที่จะเป็น "ไม่มี -- ต้องใช้คนเท่านั้น"?
การรัน autocannon กับ route /health ของ Production Server รายงานตัวเลขประมาณ 60k-75k request ต่อวินาทีบนเครื่องนี้ ตัวเลขนี้ไม่ได้บอกอะไรกับเราบ้าง?
reviewer คนหนึ่งเห็น PR ที่มีผลรัน node --test รายงานว่า "1 passed, 0 failed" สำหรับฟังก์ชันใหม่ตัวหนึ่ง แล้วถือว่านี่เป็นหลักฐานว่าฟังก์ชันนั้นถูกต้อง จากบทนี้และ AI bug catalog ช่องโหว่ในเหตุผลนั้นคืออะไร?