ข้ามไปยังเนื้อหา
Dee Wan 1.0 ยังอยู่ระหว่างพัฒนาและยังไม่เปิดตัว (pre-MVP) — ดู ขอบเขตผลิตภัณฑ์ 1.0

Scheduling แบบ end to end

ทั้งสองเซอร์วิสบนเครื่องเดียว ไม่ต้องมีบัญชี Cloudflare ไม่ต้องมี credential จริง: ติดตั้งปลั๊กอินเข้าไปใน Dee Wan บนเครื่อง local ตั้งเวลาการเผยแพร่จริง ให้ runner ดำเนินการตามรายการตั้งเวลานั้น แล้วทำให้มันล้มเหลวในแต่ละ รูปแบบที่มันควรจะล้มเหลว

README ของปลั๊กอิน คือเอกสารอ้างอิงสำหรับ route, การตั้งค่า, หลักการทำงานของการตั้งเวลา และตาราง retry หน้านี้คือลำดับขั้นตอน เอกสารฝั่ง core อยู่ใน docs/plugins/ ของ repository ของ Dee Wan — protocol v1, ความปลอดภัย, การทดสอบ

อินเทอร์เฟซของปลั๊กอิน Scheduling ยังเป็นภาษาอังกฤษ

ไม่มีขั้นตอนใดด้านล่างที่ต้องใช้โดเมนจริง token จริง หรือ Worker ที่ deploy แล้ว อย่าชี้ส่วนใดของมันไปที่ ไซต์ production

ทำตาม ชุดติดตั้งแบบสองเซอร์วิสบนเครื่อง local ใน การทดสอบปลั๊กอิน โดยใช้ปลั๊กอินนี้ เมื่อเสร็จแล้ว:

  • admin Worker ของ Dee Wan รันอยู่ที่ http://localhost:8787 และ admin UI ของมันที่ http://localhost:5173 โดยมี PLUGIN_DEV_ORIGINS=http://localhost:8788 ใน backend/.dev.vars และ local:seed พิมพ์ข้อมูลเข้าสู่ระบบออกมาแล้ว
  • ปลั๊กอินนี้รันภายใต้ npx wrangler dev --port 8788 --test-scheduled จาก plugins/scheduling โดย D1 บนเครื่อง local ของมันถูก migrate แล้ว และมี ADMIN_SECRET=local-admin-secret-0123456789 ใน .dev.vars
  • คุณถือ activation code ใหม่จาก POST /admin/activation-codes มันใช้ได้ครั้งเดียวและหมดอายุ หลัง 15 นาที ดังนั้นให้ออกใหม่หากมันหมดอายุไปแล้ว

คำสั่งด้านล่างรันจาก plugins/scheduling

เข้าสู่ระบบที่ http://localhost:5173 ด้วยบัญชีที่ local:seed พิมพ์ออกมา จากนั้น การตั้งค่า → ปลั๊กอิน → ติดตั้ง:

  • manifest URL http://localhost:8788/dee-wan/manifest.json
  • activation code จากขั้นตอนที่ 1
  • capability: ติ๊กทั้งห้าตัว สำหรับการทดลองนี้ ทุกช่องเริ่มต้นโดยไม่ได้ติ๊ก
  • โมเดล: ติ๊ก Article (หรืออะไรก็ตามที่ไซต์ที่ seed ไว้มี)

ใช้ UI แทน curl: route ด้านการดูแลระบบต้องการ session จริง header ของไซต์ และ สิทธิ์ site:plugins และ UI มีครบทั้งสามอย่าง

สิทธิ์และโมเดลที่ปลั๊กอินขอ หลังตรวจ manifest และก่อนเปิดใช้งาน

ปลั๊กอิน Scheduling ที่ติดตั้งแล้วพร้อมสิทธิ์ที่ได้รับ

สิ่งที่เกิดขึ้นตามลำดับ: Dee Wan ดึงและ validate manifest บันทึก installation ที่อยู่ในสถานะรอ ออก token แล้ว POST มันพร้อมโค้ดของคุณไปยัง http://localhost:8788/dee-wan/activate และทำเครื่องหมาย installation ว่า active เฉพาะหลังจากปลั๊กอินนี้ตอบ 2xx เท่านั้น ตรวจสอบฝั่งปลั๊กอิน:

หน้าต่างเทอร์มินัล
npx wrangler d1 execute dee-wan-scheduling --local \
--command "SELECT id, site_id, dee_wan_base_url FROM installation"

คอลัมน์ token_ciphertext เก็บ token ในรูปเข้ารหัส ไม่มีคอลัมน์ บรรทัด log หรือ route ใดในฝั่งใดที่จะแสดง token ดิบให้คุณเห็น

ใน Dee Wan: เปิดรายการ draft ในโมเดลนั้น แล้วใช้ action Schedule ที่ manifest ประกาศไว้ นั่นคือ delegated launch: Dee Wan ออกโค้ดแบบใช้ครั้งเดียว browser ของคุณไปถึง http://localhost:8788/installations/<id>?dee_wan_launch=… แบ็กเอนด์ของปลั๊กอินนี้แลกเปลี่ยนมันเป็น delegation ตั้ง session cookie ของตัวเอง และ redirect ไปยังหน้าเดิมโดยไม่มีโค้ดใน URL

ฟอร์มอ่านรายการผ่าน delegation ดังนั้น transition ที่มันเสนอคือสิ่งที่ คุณ ทำได้ในขณะนี้ เลือกเวลาท้องถิ่นล่วงหน้าหนึ่งหรือสองนาทีและเลือก timezone หน้ายืนยันแสดง ทั้งเวลาท้องถิ่นพร้อมโซนเวลา และเวลา UTC ที่คำนวณได้ ทั้งสองค่านี้เป็นข้อมูลสำคัญของการตั้งเวลา และเป็น สิ่งที่ถูกเก็บไว้ เมื่อโซนเวลาเป็น UTC ทั้งสองค่าเหมือนกัน จึงแสดงเพียงค่าเดียว

หน้าต่างเทอร์มินัล
npx wrangler d1 execute dee-wan-scheduling --local \
--command "SELECT id, kind, target_state, pinned_version_id, expected_workflow_revision, local_datetime, timezone, due_at, status FROM schedule"

pinned_version_id คือเวอร์ชันที่ตรงตัวซึ่งจะถูกเผยแพร่ — ไม่ใช่ “อะไรก็ตามที่เป็นปัจจุบันตอนที่มันรัน”

cron trigger ไม่ทำงานเองใน wrangler dev เมื่อใช้ --test-scheduled:

หน้าต่างเทอร์มินัล
curl "http://localhost:8788/__scheduled?cron=*+*+*+*+*"

หนึ่ง tick จะรับสิทธิ์ประมวลผลแถวที่ถึงกำหนดได้สูงสุด 20 แถวพร้อม lease ส่งคำสั่งหนึ่งคำสั่งต่อแถว และบันทึกผลของแต่ละแถว จากนั้น:

หน้าต่างเทอร์มินัล
npx wrangler d1 execute dee-wan-scheduling --local \
--command "SELECT id, status, attempt_count, last_code, last_message FROM schedule"
npx wrangler d1 execute dee-wan-scheduling --local \
--command "SELECT schedule_id, attempt, code, http_status FROM schedule_attempt ORDER BY attempt"

รายการตั้งเวลาที่เสร็จสมบูรณ์จะแสดง status = completed, last_code = transition_applied ใน Dee Wan รายการนั้นถูกเผยแพร่แล้ว translation group ทั้งกลุ่มถูกย้ายไปพร้อมกัน และประวัติเนื้อหาแสดง Scheduling plugin เป็นผู้กระทำ — ไม่ใช่บัญชีผู้ใช้ของคุณ และไม่ใช่บัญชีที่ถูกปลอมขึ้น

tick ก่อนถึงเวลากำหนดจะไม่ claim อะไรเลย หลังเวลากำหนด tick แรกจะทำให้รายการตั้งเวลาเสร็จสมบูรณ์ และ tick ที่สองจะไม่พบอะไรให้ทำ เพราะมีเพียงแถว pending หรือ retrying ที่ถึงกำหนด (และ แถว running ที่ lease หมดอายุแล้ว) เท่านั้นที่ถูก claim และแถวนี้ตอนนี้เป็น completed แล้ว หาก คำสั่งเดียวกันถูกส่งสองครั้ง — เช่น worker ที่ crash แล้ว lease ของมันถูก reclaim — idempotency key จะทำให้ Dee Wan ตอบ idempotent_replay แทนที่จะเผยแพร่ซ้ำ

หากต้องการดูในปฏิทิน: ปฏิทิน บน แดชบอร์ด หรือรายการ เนื้อหา หรือ การตั้งค่า → ปลั๊กอิน แล้ว เปิด บนการ์ด Calendar ในแถวของ Scheduling นั่นคือ launch แบบ manage ที่มี "view": "calendar" ไม่ต้องมี site:plugins ต้องมีเพียงโมเดลหนึ่งที่ให้ Scheduling ไว้และคุณอ่านได้ ทุกรายการหรือเฉพาะรายการของตัวเอง ผู้ที่อ่านได้แต่เผยแพร่ไม่ได้จะเห็นปฏิทินเดียวกันโดยไม่มี Reschedule และ Cancel ผู้ที่อ่านได้เฉพาะรายการของตัวเองจะเห็นเฉพาะรายการตั้งเวลาของรายการเหล่านั้น URL ของ launch มี dee_wan_view=calendar อยู่ข้างรหัส และหลังการแลกรหัส ปลั๊กอินจะ redirect ไปที่ /installations/<id>/calendar วันของรายการตั้งเวลาแสดงจำนวน ลิงก์ของวันนั้นแสดง รายการตั้งเวลาเป็น Completed พร้อม transition_applied เลือก timezone อื่นในตัวกรองเพื่อดู แถวเดียวกันในวันท้องถิ่นของ timezone นั้น

เปิด การตั้งค่า → ปลั๊กอิน แล้วกด เปิด บนการ์ด Releases ของ Scheduling (launch แบบ manage ด้วย view: releases) บนแดชบอร์ดมี ชุดเผยแพร่ เช่นกัน สร้าง Launch แล้วเพิ่มเนื้อหาจากสองโมเดลด้วย Add to release บนการ์ด Schedule เลือกเผยแพร่และภาษาเดียวหรือทั้งกลุ่มคำแปล รีลีสมีได้ไม่เกิน 25 รายการ

สำหรับรายการแบบปกติ คง Version → Latest ordinary draft ไว้ บันทึกฉบับร่างใหม่ของรายการหนึ่งแล้วโหลดรีลีสใหม่ รีลีสยังพร้อมส่งฉบับร่างปกติล่าสุด เพราะการเพิ่มรายการยังไม่ตรึงเวอร์ชัน หากรายการใดติดขัด Run now จะปิดพร้อมบอกเหตุผล รายการที่อ่านไม่ได้ขวางการเริ่มโดยไม่เปิดเผยชื่อ ให้แก้หรือนำออก รีลีสที่ตั้งเวลาไว้และติดขัดเมื่อถึงกำหนดจะเก็บ Blocked attempts และรอให้บุคคลเริ่มหรือตั้งเวลาใหม่

สำหรับรีลีสที่สอง เลือก Version → Independent future version ตอนเพิ่มการเผยแพร่ ใน Dee Wan เปิด เวอร์ชันในอนาคต เลือกรีลีสนี้ แก้ชื่อหรือส่วนของหน้าแล้วกด บันทึก ตรวจ ประวัติเวอร์ชันในอนาคต และยืนยันว่าฉบับร่างปกติยังมีเนื้อหาเดิม ตั้งเวลารีลีสแล้วใช้ ดูตัวอย่างถึงรุ่นเผยแพร่นี้ (หน้าที่ประกอบจากส่วนต่าง ๆ มีตัวอย่างในตัวแก้ไขหน้า) ตัวอย่างรวมเนื้อหาที่เผยแพร่แล้วและการเปลี่ยนจากรีลีสก่อนหน้า หากไม่มีเวลาจะได้ release_time_required ให้ตั้งเวลาต่างกันสำหรับการเปลี่ยนรายการและภาษาเดียวกัน เพื่อหลีกเลี่ยง release_time_ambiguous

เริ่มรีลีสอนาคตแล้วตรวจว่าสาขาถูกตรึง การเผยแพร่ต้องใช้เวอร์ชันนั้นพร้อมสื่อที่ตรึงไว้ และผ่านสิทธิ์ปัจจุบัน ฟิลด์ที่จำเป็น และงานตรวจสอบ หากคำตอบสูญหาย ให้ลองคำสั่งที่บันทึกไว้ซ้ำ ไม่เลือกฉบับร่างใหม่ ฉบับร่างปกติยังคงเดิม ระบบอัตโนมัติใช้ timeline-preview ส่วน release-edit ใช้ add_future สำหรับโหมดนี้ และปฏิเสธการเลิกเผยแพร่ด้วย future_requires_publish

กด Run now ตัวรันบันทึกเวอร์ชันและรีวิชัน workflow ของทุกรายการ แล้วส่งคำสั่งอะตอมมิก /releases/commit เพียงคำสั่งเดียว การเผยแพร่เปลี่ยนทั้งหมดหรือไม่เปลี่ยนเลย ตรวจบันทึกผลและแถวในฐานข้อมูลเครื่อง:

หน้าต่างเทอร์มินัล
curl "http://localhost:8788/__scheduled?cron=*+*+*+*+*"
npx wrangler d1 execute dee-wan-scheduling --local \
--command "SELECT instance_id, status, attempt, published_version_id, last_code FROM content_release_item"

รีลีสแสดง Done บันทึกผลมี release_applied และเวอร์ชันที่ใช้เผยแพร่ของแต่ละรายการ

เพื่อทดสอบการปฏิเสธ ให้เพิ่มการเลิกเผยแพร่รายการที่ยังมีเนื้อหาที่เผยแพร่แล้วนอกรีลีสอ้างอิงอยู่ ระบบหลักตอบ dependent_content และรีลีสแสดง Failed โดยทั้งการเลิกเผยแพร่และการเผยแพร่อื่นไม่เกิดขึ้น แก้ความสัมพันธ์แล้วกด Retry unfinished items เมื่อได้รับการปฏิเสธแน่ชัด ความพยายามใหม่จะอ่านเวอร์ชันล่าสุดและใช้คีย์ rel:<release>:a2

ทดสอบเผยแพร่ส่วนที่ใช้ร่วมกันพร้อมหน้าที่ใช้ส่วนนั้นในรีลีสเดียวกันทั้งสองลำดับ ทดสอบสองภาษาที่ต่างกันในกลุ่มคำแปลเดียวกันด้วย ภาษาซ้ำและการเลือกทั้งกลุ่มทับกับภาษาเดียวต้องถูกปฏิเสธ

คำตอบที่สูญหายไม่ได้หมายถึงล้มเหลวหรือสำเร็จบางส่วน ตัวรันส่งทั้งคำสั่งที่บันทึกไว้ซ้ำด้วยคีย์เดิม หากครบจำนวนลองใหม่แล้วยังไม่ทราบผล จะแสดง Outcome unknown การลองใหม่กู้ผลคำสั่งเดิมโดยไม่เดาว่ารายการใดสำเร็จ

หากต้องการตั้งเวลา ให้เลือกวัน เวลา และเขตเวลาแล้วกด Schedule tick ก่อนกำหนดไม่เปลี่ยนอะไร เมื่อถึงกำหนดจะตรวจรีลีสและส่งคำสั่งเดียว Unschedule ทำให้กลับเป็นฉบับร่าง Stop remaining items ยกเลิกงานที่ยังไม่ส่ง การเปลี่ยนแปลงที่เสร็จแล้วจะยังอยู่ และไม่สามารถย้อนคำสั่งที่ส่งไปแล้วได้

ทำแบบเดียวกันผ่าน operation ปลั๊กอิน releases, release-edit และ release-run ใน API การจัดการ CLI และ MCP ได้ โดยต้องมี site:plugins

แต่ละข้อต่อไปนี้คือสถานะจริงที่ผู้ใช้จะเจอ ทำในไซต์สำหรับทดลอง

เพื่อดู ทำสิ่งนี้ สิ่งที่คาดหวัง
scheduled_target_stale ตั้งเวลาการเผยแพร่ จากนั้นแก้ไขและบันทึก draft แล้ว tick refused ไม่มีการ retry และรายการยังคงไม่ถูกเผยแพร่
workflow_conflict ตั้งเวลาการเผยแพร่ จากนั้นเผยแพร่และยกเลิกการเผยแพร่รายการด้วยมือ แล้ว tick refused ไม่มีการ retry
transition_unavailable ตั้งเวลาการเผยแพร่ จากนั้นเผยแพร่รายการด้วยมือ แล้ว tick refused Dee Wan ตรวจการเปลี่ยนสถานะก่อน revision และรายการที่เผยแพร่แล้วไม่มีตัวเลือกให้เผยแพร่
dependent_content เผยแพร่ A เชื่อม B ที่เผยแพร่แล้วเข้ากับมัน ตั้งเวลายกเลิกการเผยแพร่ A แล้ว tick refused และ Dee Wan ระบุชื่อ dependency
requester_unauthorized ตั้งเวลาในฐานะผู้ใช้คนหนึ่ง ลบบทบาท (role) ของผู้ใช้นั้นใน Dee Wan แล้ว tick refused ระบบอ่านสิทธิ์ปัจจุบันอีกครั้งเมื่อดำเนินการ โดยไม่ใช้สิทธิ์เดิมที่เก็บไว้ตอนตั้งเวลา
plugin_unauthorized ตั้งเวลา จากนั้นปิดใช้งานหรือ uninstall ใน การตั้งค่า → ปลั๊กอิน แล้ว tick refused บันทึกด้วย last_code = plugin_unauthorized หน้าของปลั๊กอินแจ้งว่า installation ถูกนำออกหรือถูกปิด และไม่แสดงรายการตั้งเวลา
ความล้มเหลวระดับ transport หยุด admin Worker ของ Dee Wan (local:api) แล้ว tick retrying พร้อม last_code = no_response และ next_attempt_at เริ่มมันใหม่แล้ว tick หลังเวลานั้นเพื่อให้เสร็จสมบูรณ์
retry_exhausted หยุด Dee Wan และ tick จนเกิน MAX_ATTEMPTS หรือเกิน due_at + MAX_LATENESS_MS refused retry_exhausted และไม่มีอะไรถูกส่งอีกเลย
การยกเลิก ยกเลิกรายการตั้งเวลาที่รออยู่ใน UI ของปลั๊กอิน cancelled Dee Wan ไม่ถูกเรียกเลย และไม่มีอะไรถูกย้อนกลับ
รายการตั้งเวลาที่กำลังรัน ยกเลิกขณะที่ tick กำลังทำงานอยู่ execution_in_progress และ UI โหลดสถานะสุดท้ายใหม่

ตั้ง MAX_ATTEMPTS=2 และ MAX_LATENESS_MS=60000 ใน .dev.vars แล้วเริ่ม wrangler dev ใหม่ เพื่อให้ถึง เพดานภายในหนึ่งนาที แทนที่จะเป็นสิบห้านาที

Worker ที่หยุดอยู่คือความล้มเหลวระดับ transport ไม่ใช่ temporary_failure: ไม่มีคำตอบเลย จึง ไม่มี outcome code temporary_failure คือคำตอบ: Dee Wan ส่งมันเป็น outcome แบบมีโครงสร้าง เฉพาะกับ 503 และปลั๊กอินยังบันทึก 500, 502, 503 หรือ 504 เปล่าที่ไม่มี outcome ภายใต้รหัสนี้ด้วย Dee Wan บนเครื่อง local ไม่สามารถสั่งให้สร้างคำตอบทั้งสองแบบนี้ได้ตามต้องการ ชุดทดสอบของปลั๊กอินจึงครอบคลุมกรณีนี้ด้วยคำตอบจำลองที่กำหนดไว้

หลัง retry_exhausted ที่ตามหลังความล้มเหลวระดับ transport ผลลัพธ์จะ ไม่ทราบ อย่างแท้จริง — คำสั่งอาจถูกนำไปใช้แล้วโดย Dee Wan ที่ไม่สามารถตอบกลับได้ ให้ตรวจสอบรายการใน Dee Wan นั่นคือเหตุผลที่รายการตั้งเวลาแจ้งเช่นนั้น แทนที่จะอ้างว่าล้มเหลว

rotation ซึ่งผู้ดูแลระบบ (operator) ควรฝึกไว้ก่อนที่จะต้องใช้:

หน้าต่างเทอร์มินัล
curl -X POST -H "Authorization: Bearer local-admin-secret-0123456789" \
-H 'content-type: application/json' \
--data '{"installation_id":"<installation id>"}' \
http://localhost:8788/admin/activation-codes

จากนั้น การตั้งค่า → ปลั๊กอิน → หมุน ด้วยโค้ดนั้น Dee Wan ออก token ใหม่ ส่งมอบมาที่นี่ และหลังจากนั้น เท่านั้นจึงสลับ hash ที่เก็บไว้ token เก่ายังใช้ได้ในช่วงซ้อนทับที่มีขอบเขตจำกัด และ request แรกที่ ถือ token ใหม่จะยุติช่วงซ้อนทับนั้น หากปลั๊กอินนี้ปฏิเสธ token เก่ายังคงใช้งานได้ — ตรวจสอบ สิ่งนั้นด้วย โดย rotate ด้วยโค้ดที่คุณใช้ไปแล้ว

การ uninstall ใน Dee Wan จะ revoke token ทันทีและถาวร ข้อมูลของปลั๊กอินนี้ยังคงอยู่: รายการตั้งเวลาใด ๆ ที่เหลืออยู่จะปฏิเสธด้วย plugin_unauthorized เมื่อถึงกำหนด หน้าของปลั๊กอินจะหยุดแสดงรายการตั้งเวลา และแจ้งแทนว่า installation ถูกนำออกจาก Dee Wan แล้วและรายการตั้งเวลาจะไม่ทำงานอีก: เมื่อไม่ได้รับขอบเขตสิทธิ์จาก Dee Wan ปลั๊กอินไม่รู้ว่าผู้ใช้เห็นโมเดลใดได้ การระบุผู้กระทำใน audit ของ Dee Wan ก็ยังคงอยู่ เพราะ workflow event เก็บ snapshot ของ installation ไว้

หากต้องการลบข้อมูลของปลั๊กอินนี้สำหรับ installation หนึ่ง ผู้ดูแลระบบต้องร้องขอ:

หน้าต่างเทอร์มินัล
curl -X POST -H "Authorization: Bearer local-admin-secret-0123456789" \
http://localhost:8788/admin/installations/<installation id>/delete-data

มันตอบ {"deleted": true}, 404 not_found หากปลั๊กอินไม่มี installation นั้น และ 409 execution_in_progress ขณะที่รายการตั้งเวลาหรือรายการของ release ของ installation นั้นกำลังรันอยู่ ไม่มี การล้างข้อมูลตาม retention อัตโนมัติ การลบเป็นการกระทำที่ต้องมีคนทำ

หน้าต่างเทอร์มินัล
rm -rf .wrangler/state # in plugins/scheduling: the local plugin D1
npx wrangler d1 migrations apply dee-wan-scheduling --local

ฝั่ง Dee Wan reset ด้วยฐานข้อมูล local ของตัวเอง รัน npm run local:migrate ใหม่ และ npm run local:seed ใหม่ขณะที่ local:api กำลังรันอยู่

สิ่งที่การทดลองนี้พิสูจน์และไม่ได้พิสูจน์

หัวข้อที่มีชื่อว่า “สิ่งที่การทดลองนี้พิสูจน์และไม่ได้พิสูจน์”

มันพิสูจน์ว่าทั้งสองเซอร์วิสสอดคล้องกัน: manifest, activation, launch delegation, transition แบบมีเงื่อนไข ที่ถูก pin ไว้, การปฏิเสธที่มีชื่อ, retry, revocation และการลบ

มันไม่ได้พิสูจน์อะไรเกี่ยวกับการ deploy — DNS จริง latency ของ D1 จริง cron schedule จริง หรือ Worker สองตัวภายใต้โหลด และไม่ได้ใช้แทน suite ของปลั๊กอินเองได้ (npm test ใน plugins/scheduling) ซึ่งจงใจใช้ core ปลอม เพื่อให้ความล้มเหลวระบุชื่อเซอร์วิสเดียว แทนที่จะเป็นสองเซอร์วิส

npm run test:cross-service ใน plugins/scheduling รันขั้นตอนส่วนใหญ่ของการทดลองนี้โดยไม่ต้องมีคนคอยดู: Worker ทั้งสอง ตัวทำงานจริง, การติดตั้ง, delegated launch, การเผยแพร่และยกเลิกการเผยแพร่ตามกำหนดเวลา, request ที่หาย และ reply ที่หาย, scheduled_target_stale, workflow_conflict, transition_unavailable, dependent_content, การยกเลิก, isolation และการ uninstall การรันข้ามเซอร์วิสแบบอัตโนมัติ แสดงรายการสิ่งที่มันยืนยัน และสิ่งที่ยังต้องตรวจด้วยการทดลองนี้


ยังไม่เปิดตัว (pre-MVP) และยังไม่มีเวอร์ชันเสถียร
คอมมิตซอร์สโค้ด: e207e63239a627fbd2ae9c414ef7c6eb19fcfe5a (มีการแก้ไขที่ยังไม่คอมมิต)
วันที่สร้างเอกสาร (UTC): 2026-10-21T09:28:24.214Z
คอมมิตสำหรับอัปเกรด: ระบุไม่ได้: มีการแก้ไขที่ยังไม่คอมมิต. บันทึกการเปลี่ยนแปลง