`git worktree` پوشهٔ کاری را جدا میکند، اما database، port، cache، process، فایل generated، credential و cloud resource را خودبهخود جدا نمیکند. این درس چرخهٔ دقیق ساخت تا حذف worktree و یک قرارداد namespace امن برای اجرای همزمان روی `booking-platform` میسازد.
## اهداف یادگیری
پس از این درس میتوانی branch و index و shared refs را توضیح دهی، worktree را با مسیر و نام شاخهٔ قابلردگیری بسازی، وضعیت و cleanup را بررسی کنی، namespace های runtime را طراحی کنی، credential جعلی بهکار ببری و برای resource ابری مالک، TTL و rollback تعیین کنی.
## جایگاه در چرخه
در چرخهٔ `Elicit → Specify → Slice → Test → Implement → Observe → Verify → Integrate → Learn`، این درس بخشی از Implement و Integrate است. ورودی آن یک task مستقل مثل adapter اعلان است؛ خروجیاش `isolation-plan.md` و evidence قابل بازتولید است. worktree جای قرارداد task یا review نیست.
## مفهوم دقیق
یک repository میتواند چند worktree داشته باشد. هر worktree یک مسیر کاری، یک HEAD و معمولاً یک index جدا دارد. refهای repository، object database و config مشترکاند؛ بنابراین commit ساختهشده از هر worktree در مخزن قابل مشاهده است. شاخهٔ checked-out را نمیتوان همزمان در دو worktree عادی checkout کرد. همین محدودیت از یک خطای رایج جلوگیری میکند، اما فایل مشترک بیرون Git را پوشش نمیدهد. `git worktree list --porcelain` منبع واقعیت برای مسیر، HEAD و وضعیت admin است.
چرخهٔ کامل
ابتدا از ریشهٔ تمیز و شاخهٔ پایهٔ شناختهشده، worktree میسازیم:
git fetch --prune origin
git worktree add -b agent/notify-email ../wt-notify-email origin/main
git -C ../wt-notify-email status --short
git worktree list --porcelainنام branch باید task و owner را روشن کند و مسیر نباید داخل worktree دیگر باشد. سپس setup را با نسخهٔ lockfile انجام میدهیم، ولی هیچ secret واقعی کپی نمیکنیم. قبل از شروع، `git diff --check` و تست baseline اجرا میشود. در پایان، agent commit را میسازد، verifier در process تازه diff و test را میبیند، و integration owner آن را merge میکند. پس از merge یا رد شدن:
git worktree remove ../wt-notify-email
git worktree prune
git branch --delete agent/notify-emailحذف branch فقط بعد از ثبت commit یا تصمیم صریح انجام میشود؛ اگر کار ناتمام است، ابتدا `git worktree lock` و handoff ثبت میشود. `remove --force` برای فایل تغییرکرده راه recovery نیست و باید فقط پس از تأیید owner انجام شود.
مثال ضعیف و اصلاحشده
مثال بد: سه agent در سه worktree اما همگی به `localhost:5432`، database `booking_test` و cache مشترک وصلاند. branchها جدا هستند ولی migration یکی جدول دیگری را میشکند و تست سبز یک agent دادهٔ agent دیگر را میخواند.
قرارداد خوب برای `notify-email` چنین است:
workspace: ../wt-notify-email
branch: agent/notify-email
port: API=4311, DB=5541, cache=6411
database: booking_notify_email_<run-id>
cache-prefix: notify-email:<run-id>:
process: PID file + process-group cleanup
generated: .tmp/notify-email/<run-id>, never shared
credentials: EXAMPLE_TOKEN_DO_NOT_USE; no production endpoint
cloud: sandbox project booking-lab, owner, TTL=2h, budget=0برای cloud resource، نامگذاری و TTL کافی نیست: permission، region، دادهٔ synthetic، سقف هزینه، owner و دستور حذف نیز ثبت میشود. اگر محیط اشتراکی اجباری است، تغییرات destructive ممنوع، tenant و schema namespaceدار و cleanup قابلممیزی است. secret از فایل `.env.example` میآید و در log، Git یا prompt ثبت نمیشود. credential جعلی حتی اگر شبیه JWT باشد قابل استفاده در production نیست.
## سناریوی booking-platform
چهار worker روی سه رفتار reschedule و یک adapter اعلان کار میکنند. worktree هر worker branch و index خود را دارد، ولی `packages/contracts` و remote refs مشترکاند. worker reschedule فقط database ephemeral خودش را میبیند؛ adapter اعلان از `FakeNotificationProvider` استفاده میکند. هیچ worker مجاز به `RESCHEDULE_V1_ENABLED` در محیط واقعی یا token سرویس بیرونی نیست. integration owner پس از merge، fixture تازه و database تازه میسازد.
## آزمایشگاه
**ورودی:** `origin/main`، task مستقل `notify-email`، lockfile و قرارداد بالا. در sandbox یکبارمصرف اجرا کن:
git worktree add -b agent/notify-email ../wt-notify-email origin/main
git -C ../wt-notify-email diff --check
git worktree list --porcelain**خروجی مورد انتظار:** یک worktree با branch یکتا، index مستقل، baseline سبز، فایل isolation plan و هیچ secret واقعی. سپس یک فایل generated و process fake بساز، PID و مسیر آن را ثبت کن و قبل از remove آنها را پاک کن.
**Recovery:** اگر `add` بهعلت branch موجود شکست خورد، branch را rename یا مسیر موجود را با owner بررسی کن؛ force نکن. اگر process باقی ماند، process group و port را با ابزار مشاهدهٔ سیستم پیدا و فقط process دارای run-id را متوقف کن. اگر database cleanup شکست خورد، دسترسی را revoke و resource را `BLOCKED` علامت بزن؛ نام namespace را reuse نکن.
## خطاهای رایج
- تصور اینکه worktree database یا port را جدا کرده است.
- checkout کردن همان branch در دو مسیر.
- کپی کردن `.env` واقعی از worktree والد.
- حذف worktree بدون ذخیرهٔ commit و evidence.
- استفاده از `git worktree prune` برای پنهان کردن resourceهای زنده.
- استفاده از cloud project مشترک بدون TTL، owner یا budget.
## Verification
- [ ] `git worktree list --porcelain` مسیر، branch و HEAD را نشان میدهد.
- [ ] branch و index worker با worker دیگر قاطی نمیشوند.
- [ ] port، database، cache و generated path run-id مستقل دارند.
- [ ] process cleanup و recovery آزموده شده است.
- [ ] credential فقط fake و network deny-by-default است.
- [ ] cloud resource owner، TTL، budget و حذف ثبت شده است.
- [ ] بعد از merge، worktree، branch موقت و resourceهای runtime پاک یا
صریحاً handoff شدهاند.
## تمرین و Rubric
برای دو worker روی `reschedule` و `notify-sms` isolation plan بنویس. Rubric: برای هرکدام مسیر و branch یکتا، port و database و cache مستقل، generated path، process cleanup، credential جعلی، cloud TTL، owner و recovery دارد؛ shared refs را با runtime state اشتباه نمیگیرد؛ و دستور cleanup مخرب بدون تأیید ارائه نمیکند.
## چرا ایزولیشن باید قراردادی باشد؟
ایزولیشن دو لایه دارد. لایهٔ اول، state قابلثبت Git است: مسیر worktree، branch، HEAD، index و commit. لایهٔ دوم، state قابلمشاهدهٔ سیستم است: socket، PID، volume، cache key، فایل موقت و resource بیرونی. اگر لایهٔ دوم نامگذاری نشود، دو worker ممکن است هر دو branch تمیز داشته باشند ولی روی یک واقعیت اجرایی کار کنند. در این حالت merge ظاهراً موفق است، اما نتیجهٔ تست قابل تکرار نیست.
برای هر run یک شناسهٔ کوتاه و غیرحساس بسازید؛ مثلاً `run-20260905-email-01`. همین شناسه باید در نام database آزمایشی، prefix cache، نام log و directory artifact تکرار شود. شناسه نباید شامل token، نام مشتری یا دادهٔ شخصی باشد. در پایان، یک manifest کوچک ثبت کنید: چه resourceهایی ساخته شد، چه کسی مالک بود، چه زمانی منقضی میشوند و cleanup چه خروجیای داشت. این manifest بخشی از evidence است و کمک میکند resource جاافتاده بهعنوان «ناشناخته» باقی نماند.
shared refs نیز مرز مهمی دارند. دیدن commit worker دیگر مجاز است، اما تغییر دادن branch یا reset کردن ref آن بدون integration owner مجاز نیست. `git worktree prune` فقط metadataی worktreeهای مفقود را پاک میکند؛ database، container، port یا cloud object را حذف نمیکند. بنابراین prune را هرگز جای cleanup runtime ننویسید. اگر worktree قفل شده، علت قفل را بخوانید و handoff را ثبت کنید؛ force removal باید آخرین اقدام تأییدشده باشد، نه میانبری برای پنهان کردن تغییرات.
## جمعبندی
Worktree ایزولیشن Git است، نه ایزولیشن کامل اجرای برنامه. branch و index محلی هستند، refs و objectها مشترکاند، و هر resource بیرونی باید namespace و چرخهٔ عمر مستقل داشته باشد. cleanup بخشی از طراحی است، نه کار بعدی.
## منابع مستقیم
- [Git worktree documentation](https://git-scm.com/docs/git-worktree.html) — semantics، add، list، remove و prune؛ resource runtime را پوشش نمیدهد.
- [Git branch documentation](https://git-scm.com/docs/git-branch) — رفتار branch و ref؛ policy integration این درس نیست.
- [OpenAI Codex sandboxing](https://developers.openai.com/codex/sandboxing) — اصل محدودسازی محیط؛ تنظیمات دقیق وابسته به runner است.
- [NIST SSDF](https://csrc.nist.gov/pubs/sp/800/218/final) — کنترلهای توسعهٔ امن و traceability.
به زبان ساده
Git worktree branch و index را جدا میکند، اما port، database، cache، process و cloud resource همچنان ممکن است مشترک باشند. ایزولیشن واقعی به namespace، TTL، owner و cleanup قابلممیزی نیاز دارد.
مثال واقعی
در قرارداد فرضی دوره، worker اعلان `notify-email` از database نامگذاریشده با run-id و پورت جدا استفاده میکند و با `FakeNotificationProvider` کار میکند؛ worktree بهتنهایی این جداسازی را ایجاد نمیکند.