Boom Field Lab

ห้าม rm — ย้ายเข้า .archive แทน: กฎบรรทัดเดียวที่ทำให้ AI agent ลบพลาดแล้วกู้ได้

agent ที่รันเองลบไฟล์จริงได้ ผมเลยไม่ให้มันลบ ให้ย้ายเข้าโฟลเดอร์ .archive ตามวันที่แทน ผลจริงใน repo ที่ใช้สร้าง Terminal: ไฟล์ในถังพักรวมกว่า 1.3 แสนไฟล์ แต่ลบจริงถาวรที่ต้องลงบันทึกมีแค่ 4 ครั้ง — พร้อมขั้นตอนเต็มและ hook ตัวอย่าง

โดย วรัญชัย ยิ่งคำนึง (Boom) · เผยแพร่ครั้งแรก · ตรวจทานล่าสุด

ห้องเก็บเอกสารมืด กล่องเรียงบนชั้นเหล็ก มีโคมไฟดวงเดียว พร้อมข้อความ ห้าม rm ย้ายเข้าถังพักแทน

ผมเคยเห็น agent ตีความ path ผิดแล้วสั่งลบโฟลเดอร์ที่ไม่ควรลบ วันนั้นมันอยู่ในกล่องทดลอง ของจริงไม่หาย แต่คำถามที่ค้างในหัวคือ ถ้าวันหนึ่งมันเกิดกับ index ที่ลูกค้า Boom Leverage Terminal ใช้อยู่ล่ะ

คำตอบไม่ใช่ "ทำให้ agent ไม่พลาด" — ไม่มีใครทำได้ คำตอบคือ ทำให้ความผิดพลาดกู้คืนได้ บทความนี้คือกฎที่ผมใช้จริง ตัวเลขจริง และข้อจำกัดของมัน

ทำไมต้องโฟกัสที่ "กู้กลับได้" มากกว่า "อย่าให้พลาด"?

เวลาประเมินระบบอัตโนมัติ ผมไล่ทุกการกระทำลงสองถัง: ถังที่ กด undo ได้ กับถังที่ กดไม่ได้ ของในถังแรกปล่อยให้ระบบทำเองได้ ของในถังที่สองต้องมีด่าน

rm อยู่ถังที่สองชัดเจน ลบแล้วเงียบหาย ไม่มีร่องรอยว่าใครลบอะไรเมื่อไหร่ แต่ถ้าเปลี่ยน rm เป็น mv ไปไว้ในโฟลเดอร์พักตามวันที่ การกระทำเดียวกันย้ายมาอยู่ถังแรกทันที:

rmmv → .archive/YYYY-MM-DD/
พลาดแล้วกู้ได้ไหมไม่ได้ (หรือยากมาก)ได้ในไม่กี่วินาที
มีร่องรอยไหมไม่มีมี — โฟลเดอร์ตามวันที่คือบันทึกในตัว
ต้องไว้ใจ agent แค่ไหนต้องไว้ใจ 100%ไม่ต้อง
ต้นทุนศูนย์พื้นที่ดิสก์

ต้นทุนเดียวคือพื้นที่ดิสก์ ซึ่งถูกกว่าการเสียงานหนึ่งวันมาก

กฎจริงเขียนไว้ว่าอะไร?

การ์ดข้อความจริงจาก CLAUDE.md: ห้าม rm — mv → .archive/YYYY-MM-DD/ (mirror โครงสร้าง path เดิม)
ข้อความจริงจาก File Deletion Protocol ใน CLAUDE.md ของ repo ที่ใช้คุม agent · คัดตรงตัว

ใน File Deletion Protocol ของ CLAUDE.md เขียนไว้สั้นๆ ว่า:

ห้าม rm — mv → .archive/YYYY-MM-DD/ (mirror โครงสร้าง path เดิม)

"mirror โครงสร้าง path เดิม" สำคัญกว่าที่คิด ไฟล์ src/lib/foo.ts ที่ถูกย้ายจะไปอยู่ที่ .archive/2026-09-24/src/lib/foo.ts — เวลากู้คืน ไม่ต้องเดาว่ามันเคยอยู่ที่ไหน

แล้วถังพักจะเต็มไหม? ลบถาวรได้เมื่อไหร่?

ได้ แต่ต้องผ่านเงื่อนไขครบทุกข้อ กฎชั้นนี้เรียกว่า Stage 3 และลบถาวรได้เมื่อ:

เส้นเวลาชีวิตของไฟล์ที่ถูกลบ: วันที่ 0 ย้ายเข้า .archive, วันที่ 7 พ้นช่วงกักรอบแรกสำหรับงานอัตโนมัติ, วันที่ 30 ขึ้นไปลบถาวรได้ถ้าไม่มีใครอ้างถึงและลงบันทึก
วงจรชีวิตของไฟล์ที่ถูกสั่งลบ ตาม File Deletion Protocol ใน CLAUDE.md · วันที่ 7 ใช้กับการ archive อัตโนมัติของไฟล์ที่ไม่ได้ใช้ 30 วัน
  1. อยู่ใน .archive/** แล้ว (เคยถูกตัดสินแล้วว่าเอาออกได้) หรือเป็นไฟล์ทดชั่วคราวชัดเจน
  2. mtime ≥ 1 เดือน — และห้ามใช้ atime เพราะการ grep หรือ linter อ่านไฟล์โดยไม่อัปเดต atime ทำให้ตัดสินผิด
  3. ไม่มีการอ้างถึงเลย — สแกนชื่อไฟล์ ชื่อไม่มีนามสกุล และรูปแบบ slug ทั้ง repo เจอแม้แต่ที่เดียว = เก็บไว้ (กันไฟล์ที่ถูกอ่านปีละครั้งแต่สำคัญมาก)
  4. ลงบันทึกทุกครั้ง ใน _rm_log.jsonl พร้อมเหตุผล

ส่วนการ archive อัตโนมัติของไฟล์ที่ไม่ได้ใช้ 30 วัน มีช่วงกัก 7 วันก่อน ถ้ามีการเข้าถึงในช่วงนั้นระบบย้ายกลับที่เดิมเอง

ผลจริงเป็นยังไง?

กราฟแท่งจำนวนไฟล์ในถังพัก: โฟลเดอร์ home 97,833 ไฟล์, repo กฎและ wiki 20,967 ไฟล์, data pipeline 15,145 ไฟล์ เทียบกับการลบถาวรที่ลงบันทึก 4 ครั้ง
จำนวนไฟล์ใน .archive แต่ละที่ (find -type f | wc -l) เทียบกับจำนวนบรรทัดใน _rm_log.jsonl ของ repo กฎ/wiki · วัดเมื่อ 27 ก.ย. 2026
ที่ไฟล์ใน .archive
โฟลเดอร์ home97,833
repo กฎ + wiki (27 โฟลเดอร์วันที่ ตั้งแต่ 28 ส.ค. ถึง 26 ก.ย. 2026)20,967
data pipeline ของ Terminal15,145
รวม133,945

เทียบกับการลบถาวรที่ลงบันทึกใน repo กฎ/wiki ทั้งหมด 4 ครั้ง หนึ่งในนั้นคือไฟล์ index ขนาดราว 3.6 GB ที่เขียนไม่ครบเพราะเครื่องค้างกลาง build — ของที่พิสูจน์แล้วว่าเสียและสร้างใหม่ได้ ไม่ใช่ของที่ "น่าจะไม่ได้ใช้"

ตัวเลขนี้บอกว่ากฎทำงาน: การลบแทบทั้งหมดถูกเปลี่ยนเป็นการย้าย และการลบจริงที่เหลือเป็นเคสที่มีเหตุผลเขียนไว้ทุกครั้ง

บังคับกฎนี้ด้วย hook ได้ไหม?

ได้ และถ้าคุณเพิ่งเริ่ม ผมแนะนำให้ทำ ขอบอกตามจริงว่า ในระบบของผม กฎนี้บังคับด้วย CLAUDE.md + บันทึก + การตรวจรายสัปดาห์ ยังไม่ได้ใช้ hook ที่บล็อก rm ทุกครั้ง เพราะมีงาน build ที่ต้องลบ output ชั่วคราว (เช่น __pycache__) ได้ตามปกติ

ถ้าจะใช้ hook นี่คือตัวอย่าง PreToolUse hook แบบสั้นที่บล็อก rm บน tool Bash (exit code 2 = บล็อก และข้อความ stderr ถูกส่งกลับให้ agent อ่าน ตาม เอกสาร hooks ของ Claude Code):

#!/usr/bin/env python3
# .claude/hooks/guard_rm.py — ลงทะเบียนเป็น PreToolUse (matcher: "Bash")
import json, re, sys

cmd = (json.load(sys.stdin).get("tool_input") or {}).get("command", "")
if re.search(r"(^|[;&|]\s*)(sudo\s+)?rm\s", cmd):
    print("ห้าม rm — ใช้ mv ไปที่ .archive/$(date +%F)/<path เดิม> แทน", file=sys.stderr)
    sys.exit(2)
sys.exit(0)

ข้อควรระวังถ้าใช้จริง: regex แบบนี้จับได้เฉพาะรูปแบบตรงๆ คำสั่งที่ซ่อน rm ไว้ใน script อื่นหรือใน find -delete จะหลุด — hook คือด่านที่ดี แต่ไม่ใช่ด่านเดียว ต้องมีบันทึกและการตรวจย้อนหลังคู่กันเสมอ ดูภาพรวมของด่านหลายชั้นได้ที่ ด่านอนุมัติ + hook

สรุป

กฎ "ห้าม rm ให้ย้ายแทน" ไม่ได้ทำให้ agent ฉลาดขึ้น มันทำให้ ราคาของความผิดพลาดต่ำลงจนแทบเป็นศูนย์ ซึ่งเป็นสิ่งที่คนสร้าง product การเงินควรต้องการมากกว่า agent ที่ไม่เคยพลาด เพราะอย่างหลังไม่มีอยู่จริง

BOOM FIELD LAB

อยากเห็นว่าเครื่องมือพวกนี้ประกอบร่างเป็น Terminal จริงได้ยังไง?

Workshop 60 นาที — ดูการทำงานจริงบนหน้าจอ พร้อม workbook ให้ลงมือตาม ไม่ใช่สไลด์ทฤษฎี