Workflow หลาย Repository
ผู้อ่าน: ผู้ดูแลโปรเจกต์และ agent ที่ได้รับอนุญาตให้ตั้งค่า หากต้องการใช้งานตามปกติ เริ่มที่ เริ่มใช้งาน
ใช้คู่มือนี้เมื่อ change หนึ่งเขียนโค้ดในหลาย repository หรือเมื่อ test รันจาก repository หนึ่งแต่ต้องใช้โค้ดหรือ contract จาก repository อื่น
ถ้า change ใช้ repository เดียว ให้หยุดตรงนี้แล้วทำตาม เริ่มใช้งาน ซึ่งเป็นเส้นทางที่สั้นกว่า
สถานการณ์ตัวอย่าง: change เดียวข้าม repository API และ web
หัวข้อที่มีชื่อว่า “สถานการณ์ตัวอย่าง: change เดียวข้าม repository API และ web”คุณขอให้เพิ่มฟิลด์ใหม่ในหน้าโปรไฟล์ repository ของ API ต้องส่งฟิลด์นั้นกลับมา และ
repository ของ web ต้องแสดงผล ส่วน repository contracts ที่ใช้ร่วมกันอธิบายรูปแบบ
response และห้ามแก้
การตัดสินใจ: ประกาศ scope ก่อน ก่อน Build ให้บอก (หรือยืนยัน) ว่า change นี้
เขียน repository ไหนได้ (api, app) อ่านอย่างเดียว ตัวไหน (contracts) และอะไร
ต้องมาก่อน (api ก่อน app) Change Loop จะไม่แตะ ไม่ใช้ทดสอบ และไม่ส่งมอบ
repository ที่อยู่นอกการประกาศนี้
สิ่งที่คุณเห็น:
- agent สรุป scope ก่อนที่คุณจะอนุมัติ: repository ที่เขียน repository ที่อ่าน และลำดับ
- ความคืบหน้าของ Build และ Prove แยกตาม repository check ของ web รันกับโค้ดใหม่ของ API ที่ยังไม่ส่งมอบ เพราะทั้งคู่อยู่ใน sandbox ที่แยกกัน
- ผลสุดท้ายที่ระบุว่า repository ใดถูกอ่าน เขียน พิสูจน์แล้ว และยังรอ Land
สิ่งที่คุณตัดสินใจ:
- ยืนยัน scope และลำดับของ repository (การตัดสินใจสำคัญข้อเดียว)
- อนุมัติข้อตกลง เหมือน change ทั่วไป
- สั่ง
/landครั้งเดียว ทุก repository ที่เขียนได้จะได้รับการเปลี่ยนแปลงเป็น diff ที่ยังไม่ commit; Git HEAD และ index ไม่เปลี่ยนในทุก repository ให้ตรวจ diff ของแต่ละตัวแล้ว commit ตามขั้นตอน Git ปกติ จบจริงเมื่อเป็นarchivedเท่านั้นprovenยังไม่นับ
ถ้า repository ที่อ่านขยับระหว่างทำงาน agent จะ sync และ prove ใหม่เอง คุณไม่ต้องรัน คำสั่ง sandbox หรือ sync
ส่วนต่อจากนี้คือกลไกที่ agent และผู้ดูแลโปรเจกต์ใช้
สำหรับ agent และผู้ดูแล integration
หัวข้อที่มีชื่อว่า “สำหรับ agent และผู้ดูแล integration”ก่อนอื่น แยก Scope สามชั้นให้ออก
หัวข้อที่มีชื่อว่า “ก่อนอื่น แยก Scope สามชั้นให้ออก”ไฟล์เหล่านี้ตอบคนละคำถาม และต้องตั้งค่าตามลำดับ:
| ลำดับ | Contract | คำถามที่ตอบ |
|---|---|---|
| 1 | openspec/repositories.yaml |
โปรเจกต์นี้ใช้ repository อะไรได้บ้าง |
| 2 | openspec/changes/<change>/repositories.yaml |
change นี้อ่านหรือเขียนตัวไหนได้บ้าง |
| 3 | derived provider หรือฟิลด์ใน conditional execution.yaml |
command หลักฐานตัวนี้ต้องใช้ repository อะไรบ้าง |
อย่าข้ามไปต่อ provider ก่อน เพราะ provider พิสูจน์ repository ที่ topology ไม่รู้จัก หรือ change ไม่ได้เลือกไม่ได้
1. ประกาศ Topology ระดับโปรเจกต์
หัวข้อที่มีชื่อว่า “1. ประกาศ Topology ระดับโปรเจกต์”เพิ่มทุก repository ที่ Change Loop อาจต้องแยกพื้นที่ใน
openspec/repositories.yaml:
{ "version": 1, "repositories": [ { "id": "api", "path": "services/api", "setupCommand": "npm ci" }, { "id": "app", "path": "apps/web", "setupCommand": "npm ci" }, { "id": "contracts", "path": "contracts", "mode": "read" }, { "id": "partner-sdk", "type": "external", "path": "../partner-sdk", "mode": "read", "allowOutsideRoot": true } ]}สิ่งที่ต้องรู้:
idคือชื่อคงที่ที่ task, provider, receipt และ Land ใช้ร่วมกันpathอิงจาก control repositorysetupCommandเตรียม worktree ใหม่ของ repository นั้น- path นอก control repository เช่น sibling
../sdkต้องมีallowOutsideRoot: trueส่วนtypeจะคงเป็นgit(ค่าเริ่มต้น) หรือใช้externalก็ได้ ทำงานเหมือนกัน sibling ที่เขียนได้เป็นเจ้าของ task และ Land เหมือน submodule - repository ที่ถูกเลือกทุกตัวต้อง initialize Git แล้ว
Change Loop ปฏิเสธ dependency ที่ไม่ใช่ Git เพราะมันล็อก commit และแยก directory ที่กำลังขยับอย่างตรงไปตรงมาไม่ได้
ตรวจก่อนสร้าง change:
claude-foundation repos2. เลือก Scope ของ Change
หัวข้อที่มีชื่อว่า “2. เลือก Scope ของ Change”ใน change ให้เลือกเฉพาะ repository ที่ต้องใช้:
{ "version": 1, "repositories": [ { "id": "api", "mode": "write", "dependsOn": [] }, { "id": "app", "mode": "write", "dependsOn": ["api"] }, { "id": "contracts", "mode": "read", "dependsOn": [] }, { "id": "partner-sdk", "mode": "read", "dependsOn": [] } ]}ใช้ write เฉพาะ repository ที่ change จะสร้างโค้ด ใช้ read กับ test data,
contract, SDK และ integration dependency repository แบบ read เป็นส่วนหนึ่งของ
identity ของ proof แต่ไม่ใช่เป้าหมาย Build หรือ Land
การเลือก non-root ตัวใดก็ตามทำให้ lifecycle เป็น composite รวมถึงกรณีเลือก child
เพียงตัวเดียวโดยไม่มี product work ใน root; ระบบต้องไม่ลดรูปไปใช้ Apply หรือ
archive แบบ single-root
ตรวจ selection ที่ resolve แล้ว:
claude-foundation repos <change>3. ผูก Task กับ Repository
หัวข้อที่มีชื่อว่า “3. ผูก Task กับ Repository”task implementation ทุกตัวต้องระบุ repository เจ้าของและ path ส่วน dependency ทำให้ลำดับข้าม repository ชัดเจน:
- [ ] **T001** Update API [repo:api] [kind:implementation] [paths:src/profile]- [ ] **T002** Update app [repo:app] [kind:implementation] [depends:T001] [paths:src/profile]- [ ] **T003** Verify contract [repo:app] [kind:contract] [depends:T001,T002]Change Loop compile repository selection, task, provider และลำดับ Land เป็น execution graph ให้เอง ไม่ต้องสร้างไฟล์ graph ที่สอง
4. ให้ Build สร้าง Sandbox ทั้งหมด
หัวข้อที่มีชื่อว่า “4. ให้ Build สร้าง Sandbox ทั้งหมด”คำสั่งปกติของ agent สร้าง workspace ที่เลือกพร้อมกัน:
claude-foundation advance <change> --through buildsandbox create --all และ sandbox inspect ยังเป็น operator diagnostic ใต้
help --all; ผู้ใช้ไม่ต้องเรียงคำสั่งเอง
หลัง isolation child ที่เลือกทุกตัวต้องมี runtime record ซึ่ง target, access mode,
base head และ worktree ตรงกับ catalog sandbox inspect จะแสดง missing-record,
unexpected-record, missing หรือ invalid แทนการนำ target checkout มาใช้เงียบ ๆ
การ inspect อ่าน filesystem และ Git metadata โดยตรง จึงไม่รัน git ที่ repository
ควบคุมผ่าน PATH
repository แบบ write ได้ Build worktree แยก ส่วน read และ external ที่มี Git ได้ detached worktree ที่ล็อก commit คำสั่งนี้ไม่ได้ทำให้ service ภายนอกหรือ directory ทั่วไปปลอดภัย sandbox เป็น Git workspace isolation ไม่ใช่ OS security boundary
โค้ดและ test ของ root ยังใช้ nested repository ผ่าน path ใต้ root ได้ เช่น
require('./packages/lib') ใน root sandbox Harness จะ link path ของ repository
ที่เลือกไปยัง sandbox ของ repository นั้น check ของ root จึงเห็นงานที่ยังไม่ commit
และการแก้ผ่าน path ใดก็ไปลงที่เดียวกัน ส่วน nested repository ที่ไม่ได้เลือกจะเป็น
commit ที่ gitlink ของ root บันทึกไว้ checkout จาก object ในเครื่องแม้ target ไม่เคย
initialize submodule นั้น และเป็นแบบอ่านอย่างเดียว path เหล่านี้ไม่ใช่ change ของ
root จึงไม่อยู่ใน proof, review, changed surface หรือ Land ของ root และไม่มีใคร
ต้องสร้าง link หรือ initialize submodule เอง
5. ต่อ Evidence ให้ครบ Scope
หัวข้อที่มีชื่อว่า “5. ต่อ Evidence ให้ครบ Scope”สำหรับ custom wiring ใน conditional execution.yaml, repository คือ working directory ของ provider ส่วน
repositories คือชุดทั้งหมดที่ command อ่าน:
{ "providers": { "integration": { "capability": "integration", "adapter": "command", "repository": "api", "repositories": ["api", "app", "contracts", "partner-sdk"], "command": ["npm", "run", "test:integration"] } }}Change Loop ส่ง environment สำคัญสองตัว:
FOUNDATION_REPOSITORY_ID— ID ของ repository ที่เป็น working directoryFOUNDATION_REPOSITORIES_FILE— JSON manifest ที่มี version และ map ID ทุกตัว ใน scope ไปยังpath,accessและbaseHeadที่แยกพื้นที่แล้ว
changed-surface check, review packet, provider manifest, snapshot และ Land ใช้ base ที่บันทึกชุดเดียวกัน ก่อน isolation source head ที่เลือกใช้ตั้งต้นได้ แต่หลัง isolation ถ้า child binding หายจะเป็น infrastructure failure
โค้ด provider ต้องอ่าน manifest ห้ามสมมติว่า repository ทั้งห้าของบริษัทถูก checkout เป็น sibling อยู่ในทุกเครื่อง
ชุด repository เป็นส่วนหนึ่งของ command deduplication และ identity ของ receipt
คำสั่งเหมือนกันแต่ scope ต่างกันจะรันแยก และ receipt บันทึก repositoryIds ครบ
6. Build และ Synchronize
หัวข้อที่มีชื่อว่า “6. Build และ Synchronize”วางแผน worker ขนานหลัง scope กับ dependency นิ่งแล้วเท่านั้น:
claude-foundation agents plan <change>ถ้า change อื่นทำให้ repository ที่เลือกขยับ advance จะ sync sandbox เองก่อน Prove
ส่วน sandbox sync <change> เป็น primitive สำหรับวินิจฉัยที่อยู่เบื้องหลัง sync refresh child read worktree ได้แม้ control sandbox ใช้ copy mode และรัน
setupCommand ของ repository ใหม่หลัง refresh ถ้า setup หรือ provider ทิ้ง tracked
change ไว้ใน read workspace readiness จะ fail closed
7. Prove Graph ทั้งชุด
หัวข้อที่มีชื่อว่า “7. Prove Graph ทั้งชุด”claude-foundation advance <change> --through provenproof readiness และ proof run ยังเป็น primitive สำหรับวินิจฉัย Prove รัน branch อิสระขนานกันได้และรักษา branch ที่เสร็จแล้วเมื่ออีก branch ล้ม
แต่ aggregate proof ยังต้องตรงกับ repository และ provider scope ปัจจุบันทั้งหมด
read dependency ที่ขยับต้อง sync และ prove ใหม่ Change Loop จะไม่รับรอง commit เก่า
ใต้ repository manifest ใหม่
Consumer quality ใช้ graph เดียวกันแต่ไม่เฉลี่ยคะแนนข้าม repository ต้องเพิ่ม
ทุก repository ที่ถูกเลือกไว้ใน quality/foundation-quality.json; ถ้าขาดตัวใด
ระบบจะ fail closed แต่ละ lane เก็บ commit, workspace digest, tool/config identity,
baseline และ assurance แยกกัน รัน quality run --change <change> ก่อน Prove
หรือให้ evidence bootstrap ต่อ quality config ที่ commit แล้วเป็น static-analysis
evidence ดูรายละเอียดที่ Quality gate ของโปรเจกต์
8. Land ทุก Writable Target แบบยังไม่ Commit
หัวข้อที่มีชื่อว่า “8. Land ทุก Writable Target แบบยังไม่ Commit”read repository ไม่มี Land node และผู้ใช้ให้อำนาจ local delivery ทั้ง transaction ด้วยคำสั่งเดียว:
/land <change>Harness เตรียม writable target ทุกตัวก่อนเขียนไฟล์แรก แล้ว apply projection ที่
พิสูจน์แล้วตาม dependency พร้อม durable checkpoint แต่ละ node จบที่
applied-uncommitted; Git HEAD กับ index ของทุก repository ไม่เปลี่ยน และงานเดิม
ที่ไม่ overlap ยังคงอยู่ เรียก /land ซ้ำแล้วระบบ resume transaction เดิมโดยข้าม
node ที่ตรวจแล้ว land check, land record แบบ legacy และ land resume ยังเป็น
diagnostic/compatibility primitive ไม่ใช่ขั้นที่ user ต้องเรียงเอง ส่วน commit,
push และ PR อยู่นอก Land และต้องมีอำนาจแยก
saga นี้ใช้ด้วยเมื่อเลือก non-root child เพียงตัวเดียว runtime record ที่หายต้องไม่ ทำให้ Land ลัดไปใช้ทาง single-repository
แผนที่การกู้คืน
หัวข้อที่มีชื่อว่า “แผนที่การกู้คืน”| เหตุการณ์ | Action ที่ถูกต้อง |
|---|---|
| target ที่เลือกขยับ | advance sync sandbox และ Prove ใหม่เอง |
| sync เจอ replay conflict | agent แก้ path ที่ระบุใน sandbox ไม่ต้องสร้าง change ใหม่ |
| read repository สกปรก | เอา mutation ออกหรือแก้ setup/provider |
| setup ของ repository ล้ม | Harness retry เฉพาะ repository นั้นและเก็บ sibling ที่พร้อมแล้ว; แก้ policy เฉพาะเมื่อ command ที่ประกาศผิดจริง |
| binding ของ child ที่เลือกหาย | Harness ซ่อม binding โดยรักษา worktree ที่ยังใช้ได้; ใช้ sandbox inspect เมื่อต้องวินิจฉัยเท่านั้น |
| path มาตรฐานของ child เป็น worktree ของ repository อื่น | อย่าแก้หรือลบทิ้ง ตรวจ path ที่รายงาน แล้วแก้ conflict ของ target/path หรือ abandon change อย่างชัดเจน |
| provider มองไม่เห็น repository | เพิ่มใน repositories ของ provider ห้าม hard-code local path |
| check ปฏิเสธเพราะสำเนาใน root ของ repository ที่ไม่ได้เลือกถูกแก้ | คืนสำเนานั้น (ข้อความปฏิเสธระบุคำสั่งไว้) หรือเลือก repository ผ่าน semantic amendment |
| Land ถูกขัดจังหวะ | เรียก /land <change> ซ้ำเพื่อ resume journal; งานใน root หรือ repository sandbox ที่เพิ่มหลัง delivery ก่อนหน้าจะถูก apply ใหม่ |
Land หยุดด้วย ROOT_POINTER_MOVED |
root sandbox ขยับ pointer ของ submodule ที่ change เลือกไว้: agent นำ commit เข้า sandbox ของ repository นั้น คืน root pointer เป็น base แล้ว resume |
Land หยุดด้วย repository-pointer-change |
root sandbox ขยับ pointer ของ submodule ที่ไม่ได้เลือก: ให้ user เลือกว่าจะส่ง pointer ผ่าน repository นั้น, คืน pointer เป็น base แล้ว land ส่วนที่เหลือ หรือ pause |
User และ Agent ต้องทำอะไร
หัวข้อที่มีชื่อว่า “User และ Agent ต้องทำอะไร”User: ยืนยัน scope/dependency ที่มีผลต่อ behavior, เรียก Land ครั้งเดียว, ตรวจ final diff และ commit ตาม Git process ของ project ไม่ต้องสร้าง manifest, grant, receipt, hash หรือ Land journal เอง
Agent: ตั้งค่า scope สามชั้นตามลำดับ ใช้ path จาก manifest รัน readiness ก่อน เสียรอบ Prove ทำ recovery ตามที่ระบบรายงาน และสรุปว่า repository ใดถูกอ่าน เขียน พิสูจน์แล้ว หรือยังรอ Land ห้ามให้ user คัดลอก protocol JSON และห้ามลด test ที่ต้อง ใช้ห้า repository เหลือสามตัวเพียงเพราะ sandbox มีข้อมูลไม่ครบ