# बिना टकराव के autonomous deployments के लिए rollback endpoints

Autonomous deployment agents को असफल होने की स्थिति में सुरक्षित रूप से रुकने की अनुमति चाहिए, अनुमान लगाने की नहीं। खतरनाक rollback आम तौर पर वह command नहीं होती जो विफल हो जाए। खतरा उस command में होता है जो दुनिया बदल जाने के बाद सफल हो और किसी पुराने artifact को ऐसी release के ऊपर बहाल कर दे जिसे agent ने बनाया ही नहीं था।

एक सुरक्षित rollback action किसी खास deployment attempt की पहचान करता है, किसी खास पिछली release का नाम देता है और तब काम करने से इनकार करता है जब current state के बारे में उसका view पुराना हो चुका हो। Rollback को «पिछले अच्छे version» तक पहुंचने के shortcut की तरह नहीं, बल्कि guarded state transition की तरह देखें। इसी अंतर से तय होता है कि agent अपना काम ठीक कर रहा है या किसी और का काम मिटा रहा है।

## Rollback एक ही deployment attempt से जुड़ा होना चाहिए

Rollback endpoints को reversal को उस deployment attempt से जोड़ना चाहिए जिसने संदिग्ध failure पैदा की। केवल version number यह काम नहीं कर सकता।

Teams अक्सर `1.8.4`, `1.8.5` और `1.8.6` जैसा sequence रखती हैं, फिर ऐसा operation उपलब्ध कराती हैं जो कहता है, «`1.8.4` को production में deploy करें।» Agent `1.8.5` deploy करता है और alert पाता है, फिर उस operation को कॉल करता है। इसी बीच engineer urgent release `1.8.6` deploy कर चुका होता है। Rollback endpoint request स्वीकार कर लेता है, क्योंकि `1.8.4` मौजूद है। अब production में दोनों बदलावों से पहले का artifact चल रहा है। API ने वही किया जो उससे कहा गया था, और यही समस्या है।

इन identities को अलग रखें:

- **Release** code, configuration references और metadata का immutable package है। इसे durable ID और artifact digest दें।
- **Deployment attempt** किसी named target में release डालने का एक request है। इसमें deployment ID, actor और lifecycle होते हैं।
- **Target state** वह है जो environment इस समय चला रहा है। इसमें revision या generation होता है, जो हर accepted transition पर बदलता है।
- **Rollback intent** कहता है कि deployment attempt `D` target release `R` को तभी restore कर सकता है जब `D` अभी भी current state का owner हो।

अक्सर छूट जाने वाला field ownership link है। जब deployment `dep_842`, release `rel_105` को promote करे, तो दर्ज करें कि `dep_842` ने current target generation `gen_913` बनाई। `dep_842` से जुड़ा rollback तभी आगे बढ़ सकता है जब `gen_913` current रहे। अगर बाद की deployment `gen_914` बनाती है, तो service को पुराने request से इनकार करना चाहिए।

Timestamps की तुलना करके ownership का अनुमान न लगाएं। Retries, queued workers, manual repair और user को पुरानी release चुनने देने वाली किसी भी system में clock ordering टूट सकती है। Promotion स्वीकार करते समय direct relationship store करें।

इससे एक असहज operational सवाल का जवाब भी मिलता है: क्या agent किसी दूसरे agent की deployment rollback कर सकता है? आम तौर पर नहीं। कोई अलग authority उस intervention को साफ तौर पर authorize कर सकती है, लेकिन सामान्य rollback capability केवल caller द्वारा शुरू की गई actions तक सीमित होनी चाहिए। व्यापक authority तब सुविधाजनक लगती है, जब तक दो deployment loops एक ही incident पर प्रतिक्रिया न देने लगें।

## Immutable provenance से पिछली release का पता रहता है

Service को target बदलने से पहले rollback provenance capture करनी चाहिए, क्योंकि promotion के बाद «previous» शब्द अस्पष्ट हो जाता है। Alert आने के बाद release history query करना अक्सर list में पास दिखने वाली कोई भी release चुनने का नुस्खा बन जाता है।

जब deployment service promotion स्वीकार करे, तो उसे ऐसा record बनाना चाहिए जिसमें उसी क्षण चुनी गई पिछली stable release शामिल हो। यह release तुरंत पहले हुई event से अलग हो सकती है। उदाहरण के लिए, `rel_103` stable baseline बनी रह सकती है, जबकि `rel_104` aborted experiment थी और canary के बाद `rel_105` promote हुई। सही recovery target `rel_103` हो सकता है, `rel_105` से ठीक पहले वाली row नहीं।

एक minimal record इस तरह दिख सकता है:

```json
{
  "deployment_id": "dep_842",
  "environment": "production",
  "release_id": "rel_105",
  "artifact_digest": "sha256:8b2c...",
  "source_revision": "4f1d9c7",
  "config_digest": "sha256:1a06...",
  "prior_release_id": "rel_103",
  "created_target_generation": "gen_913",
  "migration_set_id": "mig_77",
  "actor_id": "agent-run-27"
}
```

`prior_release_id` कोई सुविधा वाला field नहीं, बल्कि एक decision है। आपका promotion controller इसे ऐसे rules से चुने जिन्हें operators देख सकें: उस target के लिए आखिरी verified stable release, संभवतः compatible configuration और migration requirements के साथ। Rollback operation इसी saved decision का उपयोग करे। History table बदल जाने पर इसे दोबारा calculate न करें।

Artifact identity के लिए human release label पर्याप्त नहीं है। Tags बदल सकते हैं। Build labels गलती से दोबारा इस्तेमाल हो सकते हैं। Rollback को original attempt में दर्ज content address या उसी तरह के immutable artifact reference को deploy करना चाहिए। अगर आपका registry बाद में किसी tag को अलग bytes पर point कर सकता है, तो target release ID को promotion के समय capture किए गए digest तक resolve होना चाहिए।

Configuration के साथ भी यही सावधानी रखें। Application bytes वापस करने के साथ बदला हुआ feature flag, runtime secret reference, image pull policy या resource setting छोड़ देने पर ऐसा system बन सकता है जो testing में कभी था ही नहीं। Deployment record में हर value की duplicate copy रखना ज़रूरी नहीं, लेकिन immutable configuration revision या digest दर्ज करें और तय करें कि rollback उसे भी restore करेगा या नहीं।

Database state की सीमा अलग है। केवल nullable columns जोड़ने वाली release application rollback की अनुमति दे सकती है। Column हटाने, values rewrite करने या semantics बदलने वाली release शायद ऐसा न कर सके। अगर release planner compatibility साबित नहीं कर सकता, तो generic «full rollback» का वादा न करें। Deployment को application reversible, traffic reversible या repair required के रूप में mark करें। जिस schema को पुराना code समझ ही न सके, उसके साथ उसे चलाने से इनकार करना कम शर्मनाक है।

## Endpoint को expected current release चाहिए

Rollback request में वह release और वह live state, दोनों होने चाहिए जिन्हें वह बदलना चाहता है। इस precondition के बिना endpoint valid recovery और पुराने instruction में फर्क नहीं कर सकता।

Request contract कुछ ऐसा रखें:

```http
POST /v1/environments/production/rollbacks
Idempotency-Key: 7e4cd1ee-62cb-4efa-985f-4ee0b77d577b
Content-Type: application/json

{
  "origin_deployment_id": "dep_842",
  "expected_current_release_id": "rel_105",
  "expected_target_generation": "gen_913",
  "restore_release_id": "rel_103",
  "reason": "error rate exceeded release threshold",
  "approval_id": "apr_551"
}
```

जहां संभव हो, service को `origin_deployment_id` से `restore_release_id` निकालना चाहिए, फिर दिए गए value की stored `prior_release_id` से तुलना करनी चाहिए। Request में दोनों fields रखने से auditors agent के बताए intent को देख सकते हैं, लेकिन server record को अंतिम मानें। Caller को अपनी deployment के आधार पर कोई भी historical artifact चुनने का अधिकार कभी न दें।

सफलता पर नई deployment attempt और नई target generation लौटाएं। अगर system transition को synchronously reserve कर सकता है, तो अस्पष्ट `accepted` response न दें।

```json
{
  "rollback_deployment_id": "dep_849",
  "reverted_deployment_id": "dep_842",
  "previous_release_id": "rel_105",
  "current_release_id": "rel_103",
  "target_generation": "gen_914",
  "status": "running"
}
```

अगर live target अब मेल नहीं खाता, तो conflict response लौटाएं। Body में agent को यह report करने के लिए पर्याप्त जानकारी होनी चाहिए कि क्या हुआ, लेकिन नई action का अनुमान लगाने के लिए पर्याप्त authority नहीं।

```http
HTTP/1.1 409 Conflict
Content-Type: application/json

{
  "error": "stale_rollback",
  "origin_deployment_id": "dep_842",
  "expected_target_generation": "gen_913",
  "observed_target_generation": "gen_914",
  "observed_release_id": "rel_106"
}
```

409 एक सफल safety outcome है। Agent को सिखाएं कि इस result पर रुकना है, response को incident record में जोड़ना है और नए decision के लिए कहना है। «expected generation के बिना फिर कोशिश करें» जैसी fallback instruction न दें। इससे आपका guard केवल दिखावा बन जाएगा।

कुछ teams JSON field की जगह `If-Match` HTTP header में ETag रखती हैं। यह तभी ठीक है जब ETag target state को दर्शाता हो और हर transition पर बदलता हो। Mechanism से ज्यादा महत्वपूर्ण invariant है: command को उस state का नाम देना चाहिए जिसे वह बदल सकता है।

## Serialization दो valid requests को टकराने से रोकता है

अगर दो workers check पास करने के बाद commit कर सकते हैं, तो अकेली precondition target की सुरक्षा नहीं कर सकती। Deployment service को एक ही environment के बदलावों को serialize करना चाहिए और state store में atomic compare and swap का उपयोग करना चाहिए।

मान लें target अभी `(rel_105, gen_913)` है। Agent rollback भेजता है और operator `rel_106` भेजता है। दोनों requests `gen_913` पढ़ते हैं। अगर service application memory में check करके बाद में बिना शर्त लिखती है, तो दोनों calls success का दावा कर सकती हैं। बाद वाली write जीतती है और audit trail ऐसी state दिखाता है जो users के लिए शायद कभी रही ही नहीं।

Comparison और mutation को एक ही transaction या conditional write में रखें। Relational implementation यह pattern अपना सकती है:

```sql
UPDATE environment_targets
SET release_id = :restore_release_id,
    generation = generation + 1,
    active_deployment_id = :rollback_deployment_id,
    updated_at = CURRENT_TIMESTAMP
WHERE environment = :environment
  AND generation = :expected_generation
  AND release_id = :expected_release_id;
```

Service affected row count जांचे। एक बदली हुई row state transition reserve करती है। Zero rows का अर्थ conflict है। इसके बाद current target पढ़कर observed values को 409 response में लौटाएं।

Queue इस condition की जगह नहीं ले सकती। Queues concurrent work की संभावना घटाती हैं, लेकिन duplicate delivery, queue के बाहर का manual path या worker retry फिर भी competing commands पैदा कर सकते हैं। Conditional write वहीं रखें जहां state रहती है।

Idempotency एक अलग failure को हल करती है। Service rollback स्वीकार करने के बाद agent response खो सकता है। अगर वह उसी idempotency key के साथ retry करे, तो service को original rollback deployment और status लौटाना चाहिए। उसे दूसरी generation reserve या दूसरा execution शुरू नहीं करना चाहिए।

Idempotency को caller और endpoint तक सीमित रखें, request body का digest दर्ज करें और अलग body के साथ reused key को अस्वीकार करें। वरना buggy client identifier दोबारा इस्तेमाल करके पुराने request के साथ नया intent जोड़ सकता है।

## Rollback खराब dependency state को बनाए रख सकता है

Application rollback और environment recovery अलग operations हैं। पुराना code deploy करने वाला endpoint अपने आप हर dependency को compatible नहीं बना सकता।

मैंने इस failure का predictable रूप देखा है: release `rel_105` ने ऐसा code पेश किया जो नया enum value लिखता था। फिर migration ने database constraint को बदलकर केवल नए values की अनुमति दी। Release किसी असंबंधित कारण से विफल हुई और operator ने `rel_103` वापस रख दी। पुराने code ने पुरानी value लिखी, database ने उसे अस्वीकार कर दिया और incident बढ़ गया, क्योंकि deployment dashboard में rollback पूरा दिख रहा था।

Endpoint ने schema change नहीं किया था, लेकिन उसके success response ने गलत दावा किया। इस दावे से बचने के लिए release metadata में compatibility को ठोस terms में दर्ज करना ज़रूरी बनाएं। कम से कम यह capture करें कि restore release current data पढ़ सकती है, current data लिख सकती है और target के configuration revision के साथ चल सकती है या नहीं।

Traffic management में भी एक जोखिम है। Canary rollback को सामान्यतः केवल उसी canary के स्वामित्व वाला traffic allocation बदलना चाहिए। अगर किसी unrelated release ने stable pool बदला है या दूसरे controller ने routing rule बदला है, तो पूरा routing document लिखने वाला rollback endpoint वे बदलाव मिटा सकता है। Resource-level versions का उपयोग करें या केवल वे allocation fields patch करें जिन्हें deployment ने reserve किया था।

यही सिद्धांत infrastructure पर भी लागू होता है। अगर किसी release ने queue, bucket, role या firewall rule बनाया और बाद के काम ने उसे अपना लिया, तो reversal के दौरान उसे हटाना किसी अलग service को नुकसान पहुंचा सकता है। Cleanup के लिए resource ownership record और यह check चाहिए कि किसी बाद की deployment ने resource claim तो नहीं किया। Ownership साबित न हो सके तो resource वहीं छोड़ें और repair task बनाएं।

Irreversible operations के लिए forward repair चुनें। Agent feature flag बंद कर सकता है, traffic को दूसरी जगह भेज सकता है या corrective release deploy कर सकता है। Operators को यह जवाब पसंद नहीं आता, क्योंकि «rollback» तेज़ लगता है, लेकिन बाद के data को मिटाने वाला साफ दिखने वाला reversal repair plan से ज्यादा समय लेता है।

## Agents को सीमित authority और स्पष्ट stop point चाहिए

Autonomous agent को उतनी ही action authority दें जितनी उसके assigned deployment को पूरा करने के लिए आवश्यक हो। उसे raw cloud credentials, production access वाला general shell या arbitrary release IDs स्वीकार करने वाला endpoint नहीं चाहिए।

Release शुरू करते समय agent को deployment handle दें। यह handle status reads, health checks, deployment के allocation के भीतर traffic changes और original deployment को नाम देने वाले एक rollback को authorize कर सकता है। Deployment terminal state में पहुंचने पर या human द्वारा run revoke किए जाने पर इसे expire करें। फिर भी deployment service को server-side ownership लागू करनी चाहिए, क्योंकि handle copy हो सकता है या client खराब व्यवहार कर सकता है।

Human approval irreversible boundary से पहले होनी चाहिए, agent के irreversible command तैयार कर लेने के बाद नहीं। एक उचित policy में agent के production deployment शुरू करने पर approval मांगी जा सकती है, फिर ownership precondition बनी रहने तक उसे उसी deployment को reverse करने दिया जा सकता है। अगर agent को बाद की release मिलती है, तो किसी भी intervention के लिए उसे fresh approval चाहिए। यह रुकने की सही जगह है, क्योंकि किसी ने situation बदल दी है।

Sallyport किसी व्यक्ति की approval तक HTTP और SSH credentials को agent process से बाहर रख सकता है या हर use पर approval के लिए credential mark कर सकता है। यह control action path को सुरक्षित रखने में मदद करता है, लेकिन rollback service को अपने release और generation checks फिर भी करने होंगे। Credential custody deployment ownership तय नहीं कर सकती।

`production:rollback:any` जैसे capability names से बचें। वे caller को runtime पर scope चुनने के लिए प्रेरित करते हैं। इसके बजाय server-issued capability दें जो `dep_842`, environment `production` और specific rollback route से जुड़ी हो। Agent unrelated target मांगे तो authorization layer को deployment controller तक request पहुंचने से पहले उसे अस्वीकार करना चाहिए।

हर request के साथ agent process या workload identity दर्ज करें। Human को यह पता चलना चाहिए कि `dep_842` किसने शुरू किया, caller ने कौन-सा code sign या authenticate किया, कौन-सी approval उस पर लागू थी और execution पूरा होने से पहले किसी ने access revoke किया था या नहीं। Anonymous automation accounts हर incident को archaeology बना देते हैं।

## Verification को restored release जांचनी चाहिए, request को नहीं

Rollback तभी पूरा माना जाए जब target intended release चला रहा हो और service उन conditions की जांच कर चुकी हो जिनके कारण recovery की गई थी। HTTP 202, सफल command exit या `applied` कहने वाला controller event यह साबित नहीं करता कि पुरानी release traffic को सही तरीके से serve कर रही है।

Verification को deployment के वास्तविक failure mode के आधार पर तय करें। अगर latency या errors ने rollback शुरू कराया था, तो traffic पहुंचने के बाद उसी measurement path से restored service को observe करें। अगर worker release ने malformed jobs consume किए थे, तो worker version और controlled workload verify करें। अगर configuration error से startup failures हुए थे, तो ready instances और उनके द्वारा load किए गए configuration revision की जांच करें।

एक सीमित observation window रखें और उसका outcome दर्ज करें। Endpoint `verifying`, फिर `succeeded`, `failed` या `needs_operator` report कर सकता है। ऐसी metric के लिए हमेशा इंतज़ार न करें जो उपलब्ध ही न हो। Time limit के बाद explicit inconclusive result दें और operator decision मांगें।

Audit event को हर stage से जोड़ना चाहिए: reversal मांगने वाला alert या rule, origin deployment, expected state, conditional reservation, execution events, health evidence, final state और कोई revocation। Events में ordering और integrity controls होने चाहिए, क्योंकि विवाद के दौरान friendly deployment timeline पर्याप्त नहीं होती।

Sallyport agent runs और individual actions को encrypted hash-chained audit log में दर्ज करता है और `sp audit verify` vault key के बिना offline उस chain को जांचता है। ऐसे evidence का उपयोग यह दिखाने के लिए करें कि agent ने action मांगी थी। लेकिन क्या बदला, इसका authoritative record deployment service के state transition और verification records को ही मानें।

## परिचित rollback commands के आगे सुरक्षित wrapper रखें

`kubectl rollout undo` Kubernetes Deployment पर सीधे काम करने वाले operator के लिए उपयोगी है, लेकिन autonomous recovery के लिए यह पूरा contract नहीं है। Kubernetes के अनुसार `kubectl rollout undo` पिछले deployment revision पर लौटता है, जब तक caller `--to-revision` न दे। Manual diagnosis में यह default उचित है। लेकिन इससे यह साबित नहीं होता कि previous revision failed agent run की थी।

Kubernetes Deployment revision history को ReplicaSets में track करता है और `revisionHistoryLimit` यह नियंत्रित करता है कि Kubernetes कितनी history रखे। यह history controller artifact है, release के approved baseline, configuration compatibility या agent ownership का business record नहीं। History prune होने पर «undo» में वह revision भी नहीं मिल सकती जिसकी external deployment process को उम्मीद थी।

Agent को general `kubectl` credential देकर command को अपना rollback endpoint न कहें। Agent और cluster के बीच controller या deployment service रखें। Service को origin deployment record resolve करना चाहिए, target की live generation से तुलना करनी चाहिए, state change reserve करना चाहिए और checks पास होने के बाद ही underlying platform को call करना चाहिए।

यही बात cloud provider commands पर भी लागू होती है जो «revision X deploy करें» या CI controls जो «previous release फिर चलाएं» कहते हैं। वे platform resource पर काम करते हैं। उन्हें यह पता नहीं होता कि कोई release agent के current incident से जुड़ी है या नहीं, जब तक आपका control plane वह context उपलब्ध न कराए।

Platform command को भी सीमित रखें। अगर service named workload revision patch कर सकती है, तो उसे cluster-wide mutation देने से बचें। Broad credentials को wrapper के पीछे छिपाने से खतरा केवल दूसरी API के पीछे चला जाता है।

## Recovery automate करने से पहले release ledger बनाएं

आप हर deployment system को बदले बिना guarded rollback शुरू कर सकते हैं। पहले एक production target के लिए release ledger को authoritative बनाएं, फिर human और agent दोनों paths को उसी conditional transition से चलाएं।

एक व्यावहारिक rollout sequence में पांच हिस्से हैं:

1. Releases और deployment attempts को immutable IDs दें, फिर promotion के समय prior approved release और target generation दर्ज करें।
2. ऐसा endpoint जोड़ें जो `origin_deployment_id`, expected release, expected generation और idempotency key मांगे।
3. Database या control store में target update को conditional बनाएं और हर mismatch पर 409 लौटाएं।
4. Promotion से पहले हर release को application, configuration, data और traffic reversibility के लिए classify करें।
5. Controller rollback को complete mark करने से पहले verification evidence मांगें।

Agents को execute करने देने से पहले इस contract को report mode में चलाएं। Service को यह calculate करने दें कि वह क्या restore करती और request को reject करती या नहीं। इन decisions की तुलना वास्तविक incident actions से करें। इससे missing provenance records और hidden manual paths सामने आएंगे, बिना automation को production overwrite करने का मौका दिए।

फिर rejection को सामान्य बनाएं। Stale rollback को observed release और generation के साथ समझने योग्य incident item बनाना चाहिए, न कि ऐसा रहस्यमय failure जो किसी को endpoint bypass करने के लिए उकसाए। Endpoint तब भरोसा जीतता है जब वह unsafe request को हर बार लगातार अस्वीकार करे, यहां तक कि उसे बनाने वाले लोगों की requests को भी।

पहला field `force` नहीं, `expected_target_generation` होना चाहिए। जब आपकी deployments यह fact carry करें और original baseline सुरक्षित रखें, तब agent अपनी release को स्पष्ट सीमा के भीतर reverse कर सकता है। तब तक autonomous rollback एक पुरानी deploy command है, जिसे बदलते target की ओर चला दिया गया है।
