یک loop unattended فقط وقتی آزمایشگاهی و قابلقبول است که سقف داشته باشد. در این درس loop را به ماشین حالت تبدیل میکنیم: orient، select، implement، verify، commit و سپس `COMPLETE`، `BLOCKED` یا `DECIDE`. حداکثر هشت iteration، wall-clock و spend budget، sandbox و allowlist فرمان، جای اعتماد به «مدل خودش مراقب است» را میگیرند.
## اهداف یادگیری
پس از درس میتوانی ماشین حالت Ralph را توضیح دهی؛ سقف هشت iteration و بودجهٔ زمان/هزینه تعریف کنی؛ loop را در sandbox با command allowlist اجرا کنی؛ production credential را حذف کنی؛ verification مستقل طراحی کنی؛ و crash/restart را بدون تکرار mutation یا از دست رفتن evidence بازیابی کنی.
## جایگاه در چرخهٔ سرتاسری
این درس کنترل اجرای درسهای ۳۲ و ۳۳ است. پیش از loop باید Spec، acceptance immutable، تست protected، task graph، permission profile و recovery موجود باشد. Ralph فقط کار bounded را اجرا میکند؛ تصمیم محصول، تغییر acceptance، deploy و merge production بیرون اختیار آن است.
این ترتیب عمداً هزینهٔ آمادهسازی دارد: loop کوتاهتر از بازبینی، اما بدون قرارداد فقط سرعت تولید خطای تکرارشونده است. هر checkpoint باید به artifact قابلخواندن انسان اشاره کند.
*شکل: loop از orientation تا commit میرود و با بودجهٔ سخت به `COMPLETE`، `BLOCKED` یا `DECIDE` خارج میشود؛ متن جایگزین: ماشین حالت اجرای یک story با verification مستقل و توقف زمان/هزینه/تکرار.*
## ماشین حالت و خروجیها
`ORIENT` state و محیط را میخواند؛ `SELECT` فقط یک task آماده را انتخاب میکند؛ `IMPLEMENT` patch محدود میسازد؛ `VERIFY` تست و diff را میسنجد؛ `COMMIT` evidence را ثبت میکند. اگر acceptance و همهٔ کنترلها pass شد `COMPLETE` است. نبود dependency، crash تکرارشونده، command خارج allowlist یا budget تمامشده `BLOCKED` است. تناقض policy، acceptance یا migration که انسان باید انتخاب کند `DECIDE` است. «مدل متوقف شد» هیچکدام از این خروجیها نیست.
مثال بد
while true; do
agent --approve-all --env production
git add . && git commit -m auto
doneاین فرمان عمداً بهعنوان الگوی ناامن فقط تحلیل میشود و نباید اجرا شود: loop نامحدود، approval کلی، credential production، stage کردن فایلهای ناشناخته و نبود verifier دارد.
مثال خوب: قرارداد امن
max_iterations: 8
wall_clock: 20m
spend_budget: EXAMPLE_BUDGET_DO_NOT_CHARGE
workspace: disposable ./lab-workspace
network: deny
commands: git status, git diff --check, npm test -- --runInBand
credentials: none; no production endpoint
verification: fresh process + protected tests + human review
exits: COMPLETE | BLOCKED | DECIDEهزینهٔ نمونه را به مقدار نمادین محدود میکنیم؛ هیچ کلید یا حساب واقعی در Lab نیست. `commands` باید parser/allowlist داشته باشد، نه صرفاً جستوجوی substring؛ مسیرها، argumentها و working directory نیز validate میشوند.
## budget و safety
بودجهٔ wall-clock جلوی hang را میگیرد؛ iteration سقف retry و context churn است؛ spend budget جلوی هزینهٔ پیشبینینشده را میگیرد؛ command budget و حجم output جلوی abuse را کم میکنند. اینها correctness را ثابت نمیکنند. timeout باید process و child process را متوقف کند و state آخر را flush کند. پس از budget exit، loop اجازهٔ «یک دور آخر» ندارد.
Sandbox باید workspace disposable، user کمامتیاز، home/SSH/keychain خارج، network deny-by-default و database fixture ephemeral داشته باشد. production credential، staging write، cloud token و endpoint واقعی ممنوعاند. حتی اگر secret لازم به نظر برسد، Lab با fake adapter و `EXAMPLE_TOKEN_DO_NOT_USE` کار میکند؛ این مقدار credential نیست.
## independent verification
Agentی که patch را نوشته نباید تنها داور completion باشد. verifier تازه باید state و acceptance immutable را بخواند، diff و status را بازبینی کند، test هدفمند و سپس checks لازم را اجرا کند و خروجی را در evidence ثبت کند. `COMPLETE` یعنی همهٔ gateهای قرارداد pass شده، نه فقط process exit code صفر. اگر verifier نتواند setup را reproduce کند، خروجی `BLOCKED` است.
## سناریوی booking-platform
loop روی S2 concurrency در database محلی ephemeral کار میکند. allowlist فقط `vitest` برای تست race، `git diff --check` و خواندن `tasks.json`/Spec است. هر درخواست migration، network، تغییر acceptance، دسترسی به staging یا ارسال notification باید `DECIDE` بدهد. verifier مستقل یک fixture تازه میسازد و invariant «دقیقاً یک `200`، یک `409 SLOT_CONFLICT`، یک audit در success و zero mutation/audit در failure» را بررسی میکند.
## crash/restart recovery
قبل از هر iteration، `state.json` با `runId`, `taskId`, `iteration`, `startedAt`, `lastCommit`, `budgetRemaining` و `phase` بهصورت atomic نوشته میشود. بعد از patch، diff و خروجی test به artifact محلی میرود؛ commit فقط پس از pass verification انجام میشود. اگر process وسط کار crash کرد، session تازه `git status` و state را میخواند: diff uncommitted را بررسی و یا به checkpoint امن برمیگرداند، اما هرگز کورکورانه دوباره mutation را اجرا نمیکند. اگر commit وجود دارد، test را دوباره verify میکند و task را دوباره claim نمیکند. state ناقص یا چند commit متناقض یعنی `BLOCKED`.
## آزمایشگاه گامبهگام
**ورودی:** fixture booking، یک task S2، تست protected و فایل policy بالا. ۱. workspace یکبارمصرف و fake database بساز. ۲. allowlist را با فرمانهای بدون شبکه تنظیم کن. ۳. loop را با stub Agent و `max_iterations=8` اجرا کن. ۴. در iteration دوم process را terminate کن. ۵. session تازه را اجرا و recovery را ثبت کن. ۶. verifier مستقل را در process جدا اجرا کن.
**خروجی مورد انتظار:** log فاز، iteration، زمان باقیمانده، commit و test output؛ پایان یکی از سه signal دقیق. **Recovery:** crash با checkpoint و diff بررسی میشود؛ timeout با flush و `BLOCKED`؛ تناقض policy با `DECIDE`; test failure پس از سقف retry با `BLOCKED`. هیچ مسیر recovery به production یا credential واقعی وصل نیست.
## خطاهای رایج و نشانهها
- سقف iteration هشت است اما retry داخلی ابزار نامحدود میماند.
- timeout فقط parent را میکشد و child process ادامه میدهد.
- allowlist نام command را بررسی میکند اما argument/path را نه.
- Agent acceptance یا test را برای completion تغییر میدهد.
- verifier همان context و همان فرضهای implementer را دارد.
- crash باعث اجرای دوبارهٔ migration یا duplicate audit میشود.
## Verification
- [ ] ارجاع تصویر، alt و caption حاضر و درست است.
- [ ] loop حداکثر هشت iteration، timeout و spend budget دارد.
- [ ] sandbox، network deny و command allowlist واقعی/محدود هستند.
- [ ] production credential و endpoint در Lab وجود ندارد.
- [ ] verifier مستقل acceptance، diff و test را اجرا میکند.
- [ ] فقط `COMPLETE`، `BLOCKED` یا `DECIDE` خروجی نهاییاند.
- [ ] crash/restart با checkpoint، atomic state و بدون mutation کور recover میشود.
## تمرین و Rubric
یک loop نامحدود را که تست را تغییر میدهد و به staging token دسترسی دارد، بازطراحی کن.
**Rubric:** حداکثر ۸ iteration، wall-clock و spend budget؛ sandbox disposable و network deny؛ allowlist همراه argument؛ حذف credential production؛ acceptance immutable و verifier مستقل؛ سه خروجی صریح؛ و recovery برای crash، timeout، failure و policy ambiguity داشته باشد. صرفاً افزودن «کاربر تأیید کند» کافی نیست.
## جمعبندی
Ralph امن یعنی loopی که بتوان آن را متوقف، بازسازی و ممیزی کرد. state machine، budget، sandbox، allowlist، credential hygiene و verification مستقل با هم کار میکنند. هر ambiguity یا شکست تکرارشونده باید به انسان بازگردد، نه اینکه با retry پنهان شود.
## منابع مستقیم
- [Ralph state pattern — Geoffrey Huntley](https://ghuntley.com/ralph/) — منبع جامعهمحور pattern؛ محدودیتهای امنیتی این درس کنترل آموزشیاند.
- [Anthropic — Effective harnesses for long-running agents](https://www.anthropic.com/engineering/effective-harnesses-for-long-running-agents) — گزارش میدانی دربارهٔ state و handoff؛ ضمانت safety نیست.
- [OpenAI Codex sandboxing](https://developers.openai.com/codex/sandboxing) — مستند رسمی دربارهٔ sandbox و permission؛ profile محصولی را باید با محیط خود تطبیق داد.
- [NIST SSDF](https://csrc.nist.gov/pubs/sp/800/218/final) — چارچوب رسمی کنترلهای توسعهٔ امن؛ Ralph-specific نیست.
- [Anthropic Claude Plugins Official — Ralph Loop](https://github.com/anthropics/claude-plugins-official/tree/main/plugins/ralph-loop) — منبع رسمی کد/مستندات plugin برای Claude Code؛ سطح شواهد «مستندات و پیادهسازی رسمی محصول»، نه پژوهش مستقل دربارهٔ کیفیت یا ROI. گزینهٔ `--max-iterations` در plugin مستند شده، اما این درس سقف سخت هشت iteration و کنترلهای sandbox، spend و verification مستقل را بهعنوان قرارداد آموزشی اضافه میکند.
به زبان ساده
Ralph محدود یک ماشین حالت است: orient، select، implement، verify و commit، سپس خروجی صریح. سقف iteration و زمان، sandbox، allowlist و verifier مستقل جلوی retry بیپایان و success کاذب را میگیرند.
مثال واقعی
در اجرای فرضی S2، حداکثر هشت iteration روی database محلی ephemeral مجاز است؛ crash با خواندن `state.json` و Diff بازیابی میشود، نه با اجرای کور دوبارهٔ mutation.