ตอนนั้นเรากำลังปิดช่องโหว่ด้านความปลอดภัยอยู่ตัวหนึ่ง เป็นช่องที่อันตรายเกินกว่าจะปล่อยไว้ คือสั่ง shell ระดับ root ผ่าน Discord ได้เลย โค้ดที่แก้ก็ตรงไปตรงมา คือไปจำกัดสิทธิ์ของ worker ตัวนั้นให้เหลือแค่อ่านไฟล์ ห้ามรันคำสั่ง ห้ามแก้ไฟล์ เขียนเสร็จ อ่านทวนเองอีกรอบ ทุกอย่างดูเรียบร้อยดี
แต่พอเอาโค้ดก้อนเดิมไปให้โมเดลอีกตัวรีวิว จับได้ในไม่กี่วินาทีว่าในลิสต์สิทธิ์ที่เราเพิ่งเขียน คำสั่ง shell ดันโผล่อยู่ทั้งฝั่ง "อนุญาต" และฝั่ง "ห้าม" พร้อมกัน ช่องที่เรานึกว่าปิดสนิทแล้ว จริง ๆ ยังก้ำกึ่งอยู่ เพราะ config สองบรรทัดขัดกันเอง แก้คือลบบรรทัดที่ขัดออก ช่องโหว่ถึงปิดได้จริง
ที่น่ากลัวคือเราเป็นคนเขียน fix นั้นเอง อ่านทวนเองแล้วด้วย แต่มองไม่เห็น เพราะปักใจไปแล้วว่า "นี่คือโค้ดที่ปิดช่องโหว่" พอเชื่อแบบนั้น สายตาเลยเลื่อนผ่านบรรทัดที่ขัดกันไปเฉย ๆ ตัวที่จับได้ไม่ใช่เราที่ขยันขึ้น แต่เป็นโมเดลที่สองที่ไม่มีสมมติฐานนั้นติดมาด้วย
ช่วงที่ 1ทำไมคนเขียนถึงตรวจงานตัวเองไม่เจอ
เวลา AI เขียนโค้ดให้ มันไม่ได้แค่พิมพ์ออกมาเฉย ๆ แต่มีเหตุผลรองรับอยู่ในหัวว่าทำไมถึงเขียนแบบนั้นทุกบรรทัด พอให้กลับไปอ่านงานตัวเอง เหตุผลชุดเดิมก็ยังอยู่ครบ เลยอ่านผ่านจุดที่ผิดได้สบาย ๆ เพราะในมุมของมัน ทุกบรรทัดมีคำอธิบายหมดแล้ว
เรื่องนี้เราเคยเขียนไว้แล้วในแง่ที่ว่า ทำไม AI ถึงพูดผิดอย่างมั่นใจ โมเดลไม่ได้ตั้งใจโกหก แต่มันเก่งเรื่องหาเหตุผลมารองรับสิ่งที่ตัวเองทำไปแล้ว พอเอาความสามารถนี้มาใช้ตรวจงานตัวเอง ก็กลายเป็นทนายของโค้ดตัวเอง ไม่ใช่คนตรวจ
ทางออกไม่ใช่การจี้ให้โมเดลตัวเดิม "ตรวจให้ละเอียดขึ้น" เพราะปัญหาไม่ได้อยู่ที่ความละเอียด อยู่ที่มุมมองที่ติดมาต่างหาก ทางที่ได้ผลกว่าคือเอาโค้ดไปให้โมเดลอีกตัวอ่าน ตัวที่ไม่ได้เขียนมันมากับมือ ไม่มีเหตุผลเดิมติดหัวมาด้วย เลยเห็นสิ่งที่คนเขียนมองข้าม
นี่คือหลักการเดียวกับที่ทีมพัฒนาใช้กันมานานแล้ว คือคนเขียนกับคนรีวิวไม่ควรเป็นคนเดียวกัน พอย้ายหลักการนี้มาใช้กับงานที่ AI เป็นคนเขียนโค้ดให้ส่วนใหญ่ ก็ยังจริงอยู่ บางทีจริงกว่าเดิมด้วยซ้ำ เพราะ AI เขียนเร็วและมั่นใจกว่าคนมาก
ช่วงที่ 2ครั้งที่สอง: deploy ที่จะปล่อยของในอนาคตออกก่อนเวลา
อีกครั้งที่ตัวรีวิวช่วยไว้ เกิดกับสคริปต์ที่คุมการ deploy บล็อกนี้เอง ระบบออกแบบมาให้ปล่อยโพสต์วันละชิ้นตามคิว เราเขียนโค้ดส่วนที่ก๊อปปี้ไฟล์ทั้งโฟลเดอร์ขึ้นเซิร์ฟเวอร์ก่อน deploy แล้วก็คิดว่าจบ
พอเอา diff ไปให้ Codex รีวิว ก็ชี้จุดที่เรามองไม่เห็นเลย คือถ้าในคิวมีโพสต์ที่อนุมัติไว้แล้วแต่ยังไม่ถึงวันปล่อยอยู่หลายชิ้น การก๊อปปี้ทั้งโฟลเดอร์แล้ว deploy ครั้งเดียว จะดันโพสต์ในอนาคตทั้งหมดขึ้นเว็บพร้อมกัน คิววันละชิ้นที่ตั้งใจไว้ก็พังทันที
มองย้อนกลับไปก็ชัดมาก แต่ตอนเขียนเราโฟกัสอยู่กับ "ทำให้ deploy โพสต์วันนี้ได้" จนไม่ได้คิดว่าไฟล์อื่นในโฟลเดอร์เดียวกันจะติดไปด้วย ตัวรีวิวจัดให้เป็น P2 เราเลยแก้ด้วยการกันโพสต์ที่ยังไม่ถึงคิวออกไปก่อน แล้วค่อยเอากลับเข้ามาหลัง deploy เสร็จ
จุดที่อยากให้สังเกตคือ บั๊กสองตัวนี้คนละแบบกันเลย ตัวแรกเป็นเรื่องความปลอดภัย ตัวหลังเป็นเรื่อง logic ตอน deploy แต่ทั้งคู่เหมือนกันตรงที่ โค้ดรันผ่าน ไม่มี error และถ้าไม่มีตัวที่สองมาอ่าน ก็คงหลุดขึ้น production จริงทั้งคู่
ช่วงที่ 3ตัวที่สองไม่ได้ถูกเสมอ
ถึงตรงนี้ฟังดูเหมือนโมเดลตัวที่สองคือคำตอบของทุกอย่าง แต่ไม่ใช่ มีอีกรอบที่ตัวรีวิวยกจุดหนึ่งขึ้นมาเป็น P2 ในระบบ routing ข้อความ เราอ่านดูแล้วเช็คกับเทสต์ที่มีอยู่ ปรากฏว่าเส้นทางจริงไม่ได้พังอย่างที่เตือน สิ่งที่จับได้เป็นเคสที่แคบมากและยังเถียงได้ว่าถูกต้องตามที่ตั้งใจอยู่แล้ว สุดท้ายเราไม่ได้แก้ตามมัน
ตรงนี้แหละที่สำคัญ ตัวรีวิวที่สองไม่ใช่เจ้านาย แต่เป็นความเห็นที่สอง หน้าที่คือชี้จุดที่ควรหยุดดู ไม่ใช่ตัดสินแทนเรา ทุกจุดที่มันยกมา เรายังต้องเอาไปเทียบกับโค้ดจริงและเทสต์จริงเองอยู่ดี รับมาทุกอย่างโดยไม่คิด ก็อันตรายพอ ๆ กับไม่รีวิวเลย
เราเลยถือว่า ของที่ตัวรีวิวเตือน คือรายการที่ต้องไปยืนยันเอง ไม่ใช่รายการที่ต้องแก้ทั้งหมด ตัวที่ผ่านการยืนยันแล้วเท่านั้นถึงจะได้แก้จริง สองในสามครั้งที่เล่ามา เจอของจริง อีกครั้งเตือนเกิน นั่นคืออัตราที่ใช้งานได้ ตราบใดที่คนยังเป็นคนกดยืนยัน
ช่วงที่ 4ตั้งโมเดลตัวที่สองให้รีวิวก่อน merge
หลักการที่กลั่นได้จากสามครั้งนี้พูดได้ประโยคเดียว คือก่อน merge ทุกครั้ง เอา diff ไปให้โมเดลที่ไม่ได้เป็นคนเขียนโค้ดนั้นอ่านก่อน ส่วนที่เหลือคือทำยังไงให้หลักการนี้เกิดขึ้นทุกครั้งจริง ๆ ไม่ใช่แค่ตอนที่นึกได้
สิ่งที่เราตั้งไว้มีไม่กี่ข้อ ข้อแรกคือให้มันรันแบบ headless คือรันคำสั่งเดียวจบ ตัวรีวิวจะอ่าน repo อ่าน diff รันเทสต์เอง แล้วคืนผลออกมาเป็นจุด ๆ พร้อมระดับความรุนแรง เพราะถ้าต้องนั่งเปิดแชตคุยกับมันทุกครั้ง สุดท้ายก็จะขี้เกียจทำ
ข้อสองคือ งานรีวิวไม่เคยลดสเปกโมเดลเพื่อประหยัด งานอื่นเราเลือกโมเดลตามความยากได้ แต่ตอนรีวิวเราบังคับให้ใช้โมเดลตัวแรงสุดกับการคิดระดับสูงสุดเสมอ เพราะจุดประสงค์ทั้งหมดของขั้นนี้คือจับสิ่งที่คนเขียนมองข้าม จะปล่อยให้ตัวรีวิวมองข้ามตามคนเขียนไปอีกก็ไม่มีประโยชน์
ตัวที่เราใช้เป็นโมเดลที่สองคือ Codex ของ OpenAI เพราะมันมีคำสั่งรีวิว diff ในตัวอยู่แล้ว และที่สำคัญกว่าคือมันมาจากคนละค่ายกับตัวที่เขียน คนละค่ายแปลว่าจุดบอดคนละชุด นั่นคือเหตุผลทั้งหมดที่เราเอามาตรวจกันและกัน ส่วนรายละเอียดว่าเราห่อมันเป็นสคริปต์ของเรายังไง บังคับโมเดลกับตั้ง config ตรงไหน อันนั้นเป็นส่วนที่เรากำลังทำเป็นเครื่องมือของตัวเองต่อ แต่ตัวหลักการกับโครงเป็นแบบนี้
ถ้าจะลองเอาไปใช้ เริ่มจากจุดเดียวก่อนก็ได้ คือครั้งหน้าก่อนจะ merge งานที่ AI เขียนให้ อย่าเพิ่งเชื่อตัวที่เขียน ลองเปิดโมเดลอีกตัวขึ้นมา โยน diff ให้มันอ่าน แล้วถามคำถามเดียวว่า "มีอะไรที่คนเขียนน่าจะมองข้ามไหม" เท่านั้นก็พอเห็นแล้วว่าทำไมคนเขียนกับคนตรวจไม่ควรเป็นตัวเดียวกัน
- ทั้งสองเคสในบทความนี้ (ช่องโหว่ที่มีคำสั่ง shell อยู่ทั้งฝั่งอนุญาตและฝั่งห้าม มิ.ย. 2026 และบั๊ก deploy ที่จะปล่อยโพสต์ในคิวออกก่อนเวลา 23 มิ.ย. 2026) มาจากงานจริงบน fleet ของเราเอง จับได้ผ่านการรัน
codex reviewบน diff จริงและ fix ที่ commit ไปแล้วทั้งคู่ ไม่ได้สมมติขึ้น - คำสั่ง
codex reviewที่รันแบบ headless (อ่าน repo + diff + รันเทสต์เอง) เราทดสอบเองกับ codex-cli (มิ.ย. 2026) บนทั้ง Mac และเซิร์ฟเวอร์