دسکتاپ، Worker و محاسبات محلی · فصل ۵ — Reconciliation، Rollout و Watchdog · 189

Desired State و Drift Reconciliation

اپ یا worker محلی را اجرا می‌کند اما device identity، privilege، offline state و fleet behavior را طراحی نکرده است. موضوع جاری: «Desired State و Drift Reconciliation». می‌تواند «Desired State و Drift Reconciliation» را برای یک node محلی با identity، state، privilege و recovery boundary مناسب طراحی کند.

Desired State and Drift Reconciliation — en-US

خلاصهٔ درس

اپ یا worker محلی را اجرا می‌کند اما device identity، privilege، offline state و fleet behavior را طراحی نکرده است. موضوع جاری: «Desired State و Drift Reconciliation».

می‌تواند «Desired State و Drift Reconciliation» را برای یک node محلی با identity، state، privilege و recovery boundary مناسب طراحی کند.

خروجی این درس

می‌تواند «Desired State و Drift Reconciliation» را برای یک node محلی با identity، state، privilege و recovery boundary مناسب طراحی کند.

پیش‌نیازها

1. Process alive به معنی Desired State نیست

Node N-24 می‌تواند heartbeat سالم بدهد اما worker روی build 7.3 باشد، در حالی که desired generation می‌گوید build 7.4 و config digest برابر D7 لازم است. بنابراین «process alive» فقط یک observation محدود است؛ reconciliation باید exact desired binding، fresh observed snapshot و post-action proof داشته باشد. یک command موفق یا service status سبز، به‌تنهایی convergence را ثابت نمی‌کند.

2. مرز مالکیت LOC-016

این درس فقط Desired-State Drift Reconciliation Ledger v1 را مالک است: desired state → fresh observation → ownership classification → authorized/idempotent action → fresh convergence probe. rollout مرحله‌ای در LOC-017 است و backup/watchdog در LOC-018. اگر evidence از آن درس‌ها وارد gate شود، فقط به‌عنوان ورودی استفاده می‌شود؛ منطق آن‌ها اینجا بازتعریف نمی‌شود.

3. Desired State را با generation و digest ببند

desired_generation نشان می‌دهد با کدام نسخه منطقی از intent کار می‌کنی و desired_digest محتوای همان intent را bind می‌کند. اگر فقط نام نسخه یا generation را نگه داری ولی digest عوض شده باشد، repair می‌تواند بر مبنای intent دیگری اجرا شود. هر تصمیم باید به هر دو مقدار و provenance قابل‌ردیابی متصل باشد.

4. Observation باید Fresh باشد

Heartbeat تازه، freshness کل snapshot را ثابت نمی‌کند. observed_at و observation_ttl باید مشخص کنند آیا package version، config، service settings و policy inputها هنوز برای تصمیم معتبرند یا نه. اگر snapshot از TTL عبور کرده باشد، drift هرچقدر واضح به‌نظر برسد، تصمیم repair باید BLOCKED بماند تا observation تازه تولید شود.

5. Drift را قبل از Action طبقه‌بندی کن

هر difference یک repair target نیست. برای هر resource_key، مالکیت را جدا کن: MANAGED برای فیلدهایی که MAKNOW مجاز به reconcile است، OPERATOR_OWNED برای overrideهایی که انسان/عملیات مالک آن است، و UNKNOWN وقتی مالکیت اثبات نشده. overwrite فوریِ هر تفاوت، مرز اختیار را نابود می‌کند.

6. Operator-owned exception را حفظ کن

فرض کن همه فیلدهای مدیریت‌شده با desired state match هستند اما maintenance mode به‌صورت محلی و تأییدشده تغییر کرده است. reconcile loop نباید برای «زیبا کردن diff» آن را برگرداند. Ledger باید exception و provenance آن را ثبت کند و managed convergence را جدا از operator-owned state بسنجد.

7. Validation را از Enforcement جدا نگه دار

Google VM Manager در OS Policy بین Validation و Enforcement تفکیک می‌کند؛ DSC نیز Get/Test/Set را جدا می‌کند. این‌ها reference pattern هستند: اول تشخیص بده، بعد مجوز و precondition را بسنج، سپس فقط اگر boundary اجازه داد action انجام بده. Detection به‌تنهایی authorization نیست.

8. Action باید Idempotent و Content-bound باشد

authorized_action باید به resource و desired digest متصل باشد و idempotency_key تکرار امن همان intent را ممکن کند. اگر همان desired generation پس از convergence دوباره replay شد، loop نباید تغییر جدیدی بسازد؛ نتیجه باید نشان دهد state قبلاً converged است و action مجدد لازم نیست.

9. Retry باید Budget و Backoff داشته باشد

Retry بی‌نهایت reconciliation نیست؛ oscillation پنهان است. attempt_count، retry_budget و backoff را ثبت کن. اگر post-action observation هنوز با desired digest فرق دارد اما budget باقی است، state می‌تواند RETRY باشد. وقتی budget تمام شد یا writer متعارض ادامه داد، loop باید BLOCKED یا CONFLICT شود.

10. Conflicting Writer را با Drift ساده اشتباه نگیر

اگر یک managed field بلافاصله پس از repair دوباره توسط writer دیگری تغییر کند، مشکل صرفاً «drift باقی‌مانده» نیست. باید evidence writer conflict ثبت شود و repair loop متوقف شود؛ ادامه overwrite می‌تواند دو controller را وارد oscillation کند. CONFLICT یک state واقعی است، نه خطایی که با retry بیشتر مخفی شود.

11. Command Success با Convergence فرق دارد

ممکن است package installer exit code صفر بدهد اما snapshot بعدی هنوز digest قدیمی را نشان دهد. آن command فقط execution evidence است. post_action_observation باید fresh باشد و convergence_status را از observed state استخراج کند. تا وقتی desired و observed روی owned fields match نشده‌اند، CONVERGED مجاز نیست.

12. Ledger باید Reason و Recheck Trigger داشته باشد

برای هر تصمیم، reason و recheck_trigger لازم است. BLOCKED بدون اینکه بگوید چه evidenceی باید تازه شود، عملیاتی نیست. مثال: «snapshot stale؛ بعد از refresh observation دوباره ارزیابی کن» یا «conflicting writer؛ پس از resolve مالکیت controller دوباره بررسی کن».

13. Worked Example: Build 7.3 و Config D7

N-24 باید build 7.4 و digest D7 داشته باشد. snapshot تازه build 7.3 را نشان می‌دهد و maintenance override نیز وجود دارد. build یک managed drift است؛ maintenance override operator-owned است. repair فقط build را تغییر می‌دهد، سپس snapshot تازه build 7.4 + D7 را اثبات می‌کند و override دست‌نخورده می‌ماند. حالا managed state می‌تواند CONVERGED شود.

14. Failure Probeهای قطعی

چهار mutation را اجرا کن: snapshot را از TTL قدیمی‌تر کن ولی heartbeat را سالم نگه دار؛ فقط operator-owned maintenance field را تغییر بده؛ همان desired generation را پس از convergence replay کن؛ و command success بده ولی post-action digest را متفاوت نگه دار. خروجی باید به‌ترتیب freshness، ownership، idempotency و observed convergence را مستقل بسنجد؛ هیچ shortcut نباید success بسازد.

15. Transfer: بازگشت Node پس از دو روز Offline

Node دو روز آفلاین بوده و با desired generation قدیمی برمی‌گردد، در حالی که یک maintenance override محلی نیز تأیید شده است. اول desired authority را refresh کن، سپس snapshot تازه بگیر و ownership را دوباره طبقه‌بندی کن. baseline decision را کپی نکن. اگر desired generation محلی قدیمی است، تا refresh شدن intent تصمیم BLOCKED می‌ماند؛ override معتبر نیز نباید overwrite شود.

ارزیابی

پاسخ‌نامه‌ی این درس در بسته‌ی آموزش وجود ندارد؛ خودت جواب بده و صادقانه علامت بزن. «نیاز به مرور» درس را به صف تکرار می‌فرستد.

F1 retrieval

lesson ✗AI ✗notes ✗

F2 diagnosis

lesson ✗AI ✗notes ✗

S1 application

lesson ✗AI ✗notes ✗

S2 diagnosis

lesson ✗AI ✗notes ✗

S3 decision

lesson ✗AI ✗notes ✗

S4 transfer

lesson ✗AI ✗notes ✗
ملاک‌های ارزیابی (rubric)
DimensionSufficient evidenceBlocking failure
Desired bindingexact desired generation and digest are traceablelabel or generation is used without content binding
Fresh observationobserved_at and TTL prove decision-time freshnessheartbeat substitutes for full-state freshness
Ownershipmanaged, operator-owned, and unknown fields remain distinctevery diff is overwritten automatically
Idempotent bounded actionaction has preconditions, idempotency key, retry budget, and backoffunbounded retry or duplicate effect is allowed
Convergence + transferfresh post-action evidence proves owned convergence and transfer is recomputedcommand success or copied baseline decision is treated as proof

منابع و تازگی

·
·
·

مطالعهٔ موارد (case studies)

تصاویر درس

LOC-016-RECONCILE-FLOW

فایل‌های آزمایشگاه

Implement evaluate(case) in starter.py using only the visible synthetic evidence.

Return these fields: desired_binding, observation_state, drift_state, action_state, convergence_status, decision, audit_event, and reason.

Do not infer convergence from heartbeat or command success. Preserve operator-owned fields, stale observations, conflicting writers, and retry limits explicitly.