# क्या agent approvals के लिए Touch ID fallback paths सुरक्षित हैं?

Touch ID approval flows सामान्य तरीकों से fail होते हैं: laptop का lid बंद होता है, external keyboard सही प्रकार का नहीं होता, sensor उंगली को पहचान नहीं पाता, या बार-बार failure के बाद macOS biometry को lock कर देता है। अगर agent इन स्थितियों को अस्पष्ट approval state में बदल सकता है, तो system पहले ही खतरनाक गलती कर चुका है। Fallback path को साफ बताना चाहिए कि action अभी pending है, निश्चित रूप से deny हुआ है, या किसी अलग authentication event की प्रतीक्षा कर रहा है।

यह सुनने में interface का काम लगता है, जब तक agent के पास SSH capability न हो या वह authenticated API request तैयार न कर रहा हो। तब हर अस्पष्ट state operational behavior बन जाती है। Gateway सटीक result दिए बिना agent «बाद में फिर कोशिश करें» को नहीं समझ सकता। जब सामने जिद्दी biometric prompt हो और यह भी स्पष्ट न हो कि request अभी सक्रिय है या नहीं, तब इंसान भी खराब निर्णय लेते हैं।

मैं जिस design rule का इस्तेमाल करता हूं, वह सरल है: biometric failure request को देर करा सकता है, लेकिन authority कभी नहीं बढ़ा सकता। Sensor न मिलने पर route human decision की ओर बदल सकता है, लेकिन agent को कमजोर route चुनने की अनुमति कभी नहीं मिलनी चाहिए। Locked credential vault secret-backed काम को तब तक रोकता है, जब तक उसकी तय gate फिर से न खुले।

## Touch ID उपलब्ध होना approval के समान नहीं है

Touch ID यह बताता है कि macOS इस समय biometric sensor के ज़रिए किसी व्यक्ति की पुष्टि कर सकता है या नहीं। Approval यह तय करता है कि पुष्टि किया गया व्यक्ति इस agent process या proposed action को authorize करता है या नहीं। दोनों को एक ही event मानने से खराब fallback behavior पैदा होता है, क्योंकि failure के कारण अलग-अलग layers से जुड़े होते हैं।

Per-session approval एक सरल human decision हो सकता है: व्यक्ति requesting process की identity पढ़ता है और run को स्वीकार या अस्वीकार करता है। Per-call approval फिर से पूछा जाता है, क्योंकि credential owner ने उस खास key को इतना sensitive माना है कि इसके लिए approval जरूरी है। इनमें से कोई भी decision यह नहीं बताता कि encrypted credential vault उपलब्ध है। Vault locked रह सकता है, Mac login window पर हो सकता है या physical sensor तक पहुंच न हो सकती है।

Sallyport इस separation को केवल दिखावटी नहीं, उपयोगी बनाए रखता है। इसका vault gate absolute है: vault locked होने पर हर action deny होता है। Per-session authorization और per-call keys केवल तब agent authority तय करते हैं, जब वह gate action की अनुमति दे। इसलिए एक आकर्षक approval card locked vault के चारों ओर back door नहीं बन सकता।

यह distinction एक आम लेकिन लापरवाह सलाह को भी रोकता है: «अगर Touch ID fail हो, तो सामान्य approval button दिखा दें।» यह उस human authorization prompt के लिए सही हो सकता है, जिसे click की अनुमति देने के लिए बनाया गया हो। अगर failing Touch ID request credential vault access को सुरक्षित रखती है, तो यह गलत है। एक ही screen पर दोनों concepts हो सकते हैं, लेकिन उनके state changes अलग होने चाहिए।

Agent protocol में भी अलग states रखें:

- `awaiting_human_approval` का अर्थ है कि action अभी चला नहीं है और इंसान पहचानी गई request को approve या reject कर सकता है।
- `awaiting_vault_unlock` का अर्थ है कि secret boundary बंद होने के कारण action आगे नहीं बढ़ सकता।
- `denied` का अर्थ है कि gateway इस request के लिए authority बनाए नहीं रखेगा।
- `expired` का अर्थ है कि request ने बहुत देर तक wait किया और उसे फिर से propose करना होगा।

इन चारों states को «approval required» न कहें। यह phrase agent के लिए सबसे जरूरी बात छिपा देता है: उसे wait करना है, रुकना है या नई request तैयार करनी है।

## Clamshell mode built-in sensor तक पहुंच हटा देता है

बंद MacBook lid built-in Touch ID sensor तक physical पहुंच को असंभव बना देता है। Apple macOS पर inaccessible built-in biometric sensor के मौजूदा उदाहरण के रूप में clamshell mode का उल्लेख करता है: external monitor और keyboard से जुड़ा बंद MacBook अपने internal Touch ID sensor का इस्तेमाल नहीं कर सकता, जब तक external keyboard में Touch ID न हो।

Coding agents चलाने वाले लोगों के लिए यह कोई edge case नहीं है। MacBook desk के नीचे या monitor के पास इसलिए रहता है, क्योंकि machine लंबे समय तक चालू रहती है। अगर approval design यह मानता है कि user power button तक पहुंच सकता है, तो वह demo में काम करेगा और रोजमर्रा के इस्तेमाल में fail होगा।

Fallback behavior तय करने से पहले desk arrangement map करें:

| Physical arrangement | Touch ID route | सही gateway behavior |
| --- | --- | --- |
| Laptop खुला | Built-in sensor तक पहुंच हो सकती है | जहां control अनुमति दे, वहां Touch ID offer करें। |
| Laptop बंद, external keyboard में Touch ID नहीं | Built-in sensor unavailable है | Scan के लिए न कहें। ऐसा approval route दिखाएं जिसकी control अनुमति देती है, या vault locked रहने तक secret-backed काम deny करें। |
| Laptop बंद, external keyboard में Touch ID है | External sensor Touch ID दे सकता है | macOS biometry को usable बताए, तभी scan offer करें। |
| Laptop बंद, Touch ID keyboard disconnected या uncharged है | कोई usable biometric path नहीं | Biometric approval को unavailable mark करें और किसी भी unavailable sensor वाला वही rule अपनाएं। |

इस table का महत्वपूर्ण शब्द «हो सकती है» है। Hardware मौजूद होना उसकी वर्तमान usability साबित नहीं करता। Wireless keyboard बंद, disconnected, किसी दूसरे computer से paired या current user session के लिए अनुपलब्ध हो सकता है। Application को sensor छूने के लिए कहने वाली भाषा दिखाने से पहले operating system से पूछना चाहिए कि requested policy चल सकती है या नहीं।

Clamshell mode को per-call approval से per-session approval पर अपने आप जाने का कारण न बनाएं। यह बदलाव physical समस्या खत्म होने के बाद भी बना रहेगा और user को दिखे scope से अधिक authority देगा। अगर request को per-call decision चाहिए, तो उसे per-call ही रखें। अगर control अनुमति देती है तो click approval दिखाएं, अन्यथा action class के अनुसार उसे wait या fail होने दें।

«व्यक्ति scan नहीं कर सकता» और «व्यक्ति approve नहीं कर सकता» में व्यावहारिक अंतर है। सामान्य external keyboard वाला व्यक्ति card पढ़कर approval button पर click कर सकता है। One-click या Touch ID approval के लिए बनी per-call key में यह पर्याप्त है। लेकिन इससे Touch ID-gated vault unlock नहीं होता। Screen की भाषा भी उतनी ही साफ रखें: «Approval उपलब्ध है, vault locked है» सामान्य लाल failure banner से कहीं बेहतर है।

## Failed scan को एक request रोकनी चाहिए, नई authority नहीं बनानी चाहिए

एक failed fingerprint scan सामान्य बात है। सूखी त्वचा, उंगली का गलत कोण, sensor पर गंदगी और जल्दी में किया गया touch, ये सब हो सकते हैं। सही response सीमित retry state है, तुरंत denial या हमेशा सक्रिय request नहीं।

Apple का LocalAuthentication documentation simple authentication failure और biometric lockout में अंतर करता है। Failed credential check `authenticationFailed` report करता है, जबकि बहुत-सी असफल कोशिशों के बाद lockout अलग state होती है। Gateway को यह distinction बनाए रखना चाहिए, क्योंकि दोनों के recovery paths अलग हैं।

सामान्य failed scan पर original action को immutable रखें और थोड़े समय के लिए pending रखें। User को यह दिखना चाहिए कि वह क्या approve कर रहा है, किस agent process ने request की, target host या API क्या है, credential label क्या है और meaningful operation कौन सा है। Agent को timeout को failure की तरह दिखाने के बजाय machine-readable pending result मिलना चाहिए।

एक उपयोगी response इस तरह दिख सकता है:

```json
{
  "status": "awaiting_human_approval",
  "request_id": "apr_7f3c",
  "reason": "biometric_retry",
  "expires_at": "2026-07-22T18:42:00Z",
  "retry_after_ms": 1500,
  "action_started": false
}
```

`request_id` को केवल credential से नहीं, पूरी proposed action से bind होना चाहिए। अगर agent `git push` चलाने की request करे और user के Touch ID retry करने के बाद remote, branch या command बदल दे, तो यह अलग request है। इसे reject करें या नया approval card मांगें। केवल इसलिए approval दोबारा इस्तेमाल करना कि वही process अभी मौजूद है, harmless retry को confused-deputy bug में बदल सकता है।

दो limits तय करें। पहली, UI attempts को इतना rate-limit करें कि faulty agent बार-बार ध्यान खींचने वाले prompts न खोल सके। दूसरी, pending request को छोटी और दिखाई देने वाली अवधि के बाद expire करें। दस मिनट बाद लौटने वाले व्यक्ति को नई render की गई request पर निर्णय लेना चाहिए, क्योंकि agent की repository state, API payload या remote system बदल चुका हो सकता है।

Retry state में agent process के पास credential material नहीं होना चाहिए। Agent intended command या request body रख सकता है, लेकिन authentication की प्रतीक्षा करते समय gateway उसे token न दे। Secret injection केवल तब हो, जब gateway approved channel operation execute करे।

अक्सर teams गलत retry loop को गलत जगह रखती हैं। वे agent को हर कुछ सेकंड में पूरी tool invocation दोहराने देती हैं। इससे duplicate cards बनते हैं, repeated API operations की संभावना बढ़ती है और model सीखता है कि लगातार कोशिश करना hesitation के चारों ओर रास्ता है। Pending request gateway के नियंत्रण में होनी चाहिए। Agent उस request ID पर poll या wait करे। पहली request expire या deny होने तक वह नई request न बनाए।

## Sensor lockout का अर्थ है कि biometric route समाप्त हो गया

Sensor lockout का अर्थ यह नहीं है कि एक और fingerprint चाहिए। macOS बता रहा है कि user द्वारा operating system की आवश्यक recovery पूरी करने तक biometry disabled है। Apple `biometryLockout` को बहुत-सी असफल कोशिशों के बाद पहुंची state के रूप में document करता है और कहता है कि biometry unlock करने के लिए passcode चाहिए।

इसका agent actions पर सीधा असर है: Touch ID के लिए prompt देना बंद करें। Operating system sensor lock करने के बाद भी fingerprint मांगता dialog भ्रामक है और user को sensor पर और जोर से उंगली रखने के लिए प्रेरित कर सकता है। बताएं कि Touch ID बहाल करने के लिए macOS account authentication जरूरी है, फिर action class के अनुसार gateway request को समाप्त या suspend करें।

Account password को Touch ID का चुपचाप समान विकल्प न मानें। Apple की `deviceOwnerAuthentication` policy Touch ID, पास के paired Apple Watch या user के macOS password का इस्तेमाल कर सकती है। इसके विपरीत biometrics-only policy biometry unavailable, unenrolled या locked होने पर fail होती है। दोनों valid system policies हैं, लेकिन उनके security promises अलग हैं।

अगर आपके vault gate में Touch ID ही gate है, तो password fallback gate बदल देता है। अलग product design में आप macOS password को acceptable alternate authenticator मान सकते हैं, लेकिन vault boundary पर इस चुनाव को स्पष्ट रूप से बताना और लागू करना होगा। Framework का convenient default देखकर इसे अनजाने में स्वीकार न करें।

Touch ID-bound vault में lockout से इस समय waiting हर secret-backed call के लिए terminal operational result मिलना चाहिए:

```text
status: denied
reason: vault_authentication_unavailable
recovery: authenticate with macOS to restore Touch ID, then submit a new request
action_started: false
```

यह transient failed scan से जानबूझकर अधिक सख्त है। व्यक्ति को gateway approval flow के बाहर recovery action पूरा करना होगा। उस recovery के दौरान पुरानी request को जीवित रखना अस्पष्टता पैदा करता है: क्या बाद का account-password entry original SSH command को authorize कर रहा था, या केवल sensor बहाल कर रहा था? उत्तर स्पष्ट रखें। उसने sensor बहाल किया। Agent को operation फिर से request करना होगा।

जो approvals vault unlock पर निर्भर नहीं हैं, उनके लिए अलग result चुना जा सकता है। Session authorization card one-click decision के रूप में उपलब्ध रह सकता है, अगर उसका design इसकी अनुमति देता हो और action को locked secret की जरूरत न हो। UI को ठीक-ठीक बताना चाहिए कि क्या fail हुआ। «Touch ID locked है, click approval अभी उपलब्ध है» coherent message है। «Authentication failed» नहीं।

## Wait या stop को action की property बनाएं

केवल error code देखकर wait करने का निर्णय न लें। Action के consequence, freshness requirement और credential boundary की state से निर्णय करें। वही unavailable sensor harmless status query को wait करा सकता है, irreversible infrastructure command को रोक सकता है और vault-backed request को vault unlock होने तक fail करा सकता है।

मैं तीन action classes इस्तेमाल करता हूं।

### Class one: छोटी human response के लिए रोकें

Action को तभी hold करें, जब ये सभी बातें सही हों:

- Gateway ने operation शुरू नहीं किया है और credential inject नहीं किया है।
- Request की stable identity और visible expiry है।
- Approval के बाद replay करने पर user को surprise नहीं होगा, क्योंकि target और payload fixed हैं।
- Action reversible, read-only या पर्याप्त idempotent है, इसलिए थोड़ी देरी से उसका अर्थ नहीं बदलता।

उदाहरणों में private package version पढ़ना, repository की protected branch settings लाना या स्पष्ट रूप से पहचानी गई dry-run API request करना शामिल है। फिर भी hold gateway में होना चाहिए, agent के retry loop में नहीं।

### Class two: रोकें और नई request मांगें

जब delay command का व्यावहारिक अर्थ बदल दे, तब रुकें। Deployment, production database migration, force push, credential rotation, payment capture या data delete करने वाला SSH command latent approval के साथ पड़ा नहीं रहना चाहिए। बाद में उसे देखने वाले user को current context दिखाने वाला नया card मिलना चाहिए।

अगर request में ephemeral values हों, तब भी रुकें। Signed API request, one-time deployment artifact, short-lived URL या बदल चुके local workspace पर निर्भर command को stale intent से resume नहीं करना चाहिए। केवल process के समाप्त न होने से gateway यह नहीं जान सकता कि agent अभी भी वही करना चाहता है।

### Class three: Vault बंद होने पर तुरंत deny करें

Locked vault सुविधा से ऊपर है। अगर proposed HTTP call या SSH command को stored secret चाहिए और vault gate locked है, तो action को unlock के बाद automatic execution के लिए queue करने के बजाय deny करें। User vault unlock कर सकता है, फिर agent नई request submit करे। इससे causal record साफ रहता है: पहले unlock, फिर proposal, अंत में execution।

यहीं Sallyport की fixed decision ladder उपयोगी साबित होती है। Locked रहने पर उसका vault gate हर action को deny करता है, फिर request पर per-session authorization और per-call approval लागू होते हैं। कोई policy language यह अनुमान लगाने की कोशिश नहीं करती कि delayed `curl` इतना harmless है कि biometric event के बाद उसे फिर जिंदा किया जाए।

लुभावना विकल्प execution queue है, जो user के sensor छूते ही जाग जाती है। Demo में यह smooth लगता है। वास्तविक इस्तेमाल में authentication ऐसे काम के trigger में बदल जाता है, जिसे user अब शायद करना ही न चाहता हो। Approval को ऐसा request release करना चाहिए जिसे व्यक्ति अभी भी देख सके, न कि उसकी अनुपस्थिति में बनी backlog खाली करनी चाहिए।

## External Touch ID keyboards के लिए availability check जरूरी है

External Touch ID keyboard clamshell की एक समस्या हल करता है, लेकिन दूसरी dependency जोड़ता है। Approval के समय keyboard active Mac session में मौजूद और usable होना चाहिए। इसे setup की एक बार की जानकारी नहीं, live condition मानें।

Apple के LocalAuthentication errors में removable biometric accessories के लिए `biometryDisconnected` और `biometryNotPaired` शामिल हैं। ये codes महत्वपूर्ण हैं, क्योंकि ये अनुपस्थित hardware और authentication में असफल व्यक्ति के बीच अंतर बताते हैं। Disconnected keyboard को retry attempt consume नहीं करना चाहिए और user failure rate में नहीं गिना जाना चाहिए।

UI और protocol को चार states पर अलग-अलग response देना चाहिए:

| State | व्यक्ति को क्या दिखे | Agent को क्या मिले |
| --- | --- | --- |
| Sensor ready | स्पष्ट request और Touch ID affordance | `awaiting_human_approval` |
| Clamshell mode में sensor inaccessible | built-in sensor तक पहुंच न होने की जानकारी | `approval_path_unavailable` या अनुमत click route |
| External sensor disconnected | reconnect, charge या अनुमत alternate approval method इस्तेमाल करने का prompt | `approval_path_unavailable` |
| Scan rejected | वही immutable request और retry cue | `biometric_retry` के साथ `awaiting_human_approval` |

Raw framework error names व्यक्ति को न दिखाएं, लेकिन local activity record में रखें। «External Touch ID keyboard unavailable» मददगार है। `LAError.biometryDisconnected` diagnostics और tests के लिए है।

Approval card sensor के बिना भी usable रहना चाहिए। यह security concern के साथ basic usability का भी सवाल है। Mouse, trackpad, keyboard focus और accessibility controls से व्यक्ति request reject कर सके या अनुमत click approval चुन सके। Inaccessible biometric sensor किसी व्यक्ति को ऐसा prompt न दे, जिसका उत्तर देना संभव न हो।

## Approval screen को blocked boundary का नाम लेना चाहिए

अधिकांश confusion एक ऐसे generic modal से आता है, जो हर प्रकार के authentication को दिखाने की कोशिश करता है। जिस boundary की प्रतीक्षा हो रही है, उसके अनुसार message अलग करें।

Per-session request के लिए सबसे पहले requesting process की code-signing authority दिखाएं, फिर human को स्पष्ट approve या reject choice दें। इसी क्षण व्यक्ति तय करता है कि वह agent run को काम करने देगा या नहीं। Touch ID उपलब्ध हो तो वह choice की पुष्टि कर सकता है। अगर design click की अनुमति देता है, तो clamshell mode card को dead end न बनाए।

Per-call key के लिए exact action और credential label दिखाएं। One-click approval तभी per-call decision है, जब वह एक immutable request पर लागू हो और जल्दी expire हो। केवल इसलिए कि उस desk पर Touch ID असुविधाजनक है, एक button के पीछे agent को पांच calls batch न करने दें।

Locked vault के लिए बताएं कि vault locked है और action शुरू नहीं हुआ। Message को rejected agent request की तरह न लिखें, क्योंकि human समझ सकता है कि उसे फिर click करना है। Recovery vault की घोषित authentication mechanism से होनी चाहिए। Vault खुलने के बाद secret की जरूरत वाले हर action के लिए fresh request मांगें।

अच्छा audit record इन transitions को अलग रखता है। उदाहरण के लिए:

```text
2026-07-22T18:40:12Z request.created     id=apr_7f3c channel=ssh action="git push origin main"
2026-07-22T18:40:13Z approval.pending   id=apr_7f3c method=touch_id
2026-07-22T18:40:16Z biometric.failed   id=apr_7f3c source=built_in_sensor
2026-07-22T18:41:02Z request.expired    id=apr_7f3c action_started=false
```

Action log को failed scan को authorization denial की तरह नहीं दिखाना चाहिए। यह failed authentication attempt था। Request बिना execution के expire हुई। Review के दौरान ये शब्द महत्वपूर्ण होते हैं, खासकर जब agent कहे कि वह «deploy नहीं कर सका» और operator को जानना हो कि system ने उसे block किया, user ने reject किया या किसी ने prompt पूरा नहीं किया।

Tamper-evident audit systems में agent को लौटाने से पहले state transition record करें। Sallyport अपने Sessions और Activity journals को एक encrypted, hash-chained log से project करता है और उसका `sp audit verify` command ciphertext पर offline उस chain को verify करता है। इससे बाद के reviewer को प्रमाण मिलता है कि request expire या deny हुई थी, बिना agent के अपने transcript पर भरोसा किए।

## केवल happy-path API नहीं, physical desk को test करें

Success और failure codes लौटाने वाला LocalAuthentication unit test जरूरी है, लेकिन approval flow के बारे में लगभग कुछ साबित नहीं करता। Users को परेशान करने वाली failures hardware arrangement, desktop state और agent timing के मिलने पर सामने आती हैं।

Flow पूरा घोषित करने से पहले वास्तविक Mac पर यह test sequence चलाएं:

1. Laptop खुला रखकर agent session शुरू करें, एक per-call request submit करें, उसे reject करें, फिर fresh request submit करके approve करें। Confirm करें कि rejected request कभी execute नहीं होती।
2. Lid बंद करें और external monitor के साथ बिना Touch ID वाला keyboard लगाएं। Confirm करें कि UI user को unreachable sensor छूने के लिए नहीं कहता। Click-eligible approval और vault-backed request दोनों test करें।
3. Working external Touch ID keyboard के साथ दोहराएं। Approval pending होने पर उसे disconnect या power off करें। Confirm करें कि request failed biometric attempt के बजाय unavailable hardware report करती है।
4. लगातार unsuccessful scans कराएं, जब तक macOS lockout में न चला जाए। Confirm करें कि biometric prompts बंद हो जाते हैं, secret-backed requests बाद में execution के लिए queue नहीं होतीं और recovery के लिए नई submit की गई action जरूरी है।
5. Pending request को expiry तक छोड़ें। नई request भेजने से पहले repository branch, command arguments या API payload बदलें। Confirm करें कि नई proposal को अलग request ID और नया human decision मिलता है।

हर run के बाद logs देखें। आपको एक request creation event, state changes का sequence और या तो एक execution event या कोई execution event नहीं दिखना चाहिए। एक approval signal के बाद multiple executions replay या retry defect का संकेत हैं। Missing terminal event का अर्थ है कि support staff को अनुमान लगाना पड़ेगा कि agent अभी भी wait कर रहा है या नहीं।

Cancellation भी test करें। Touch ID unavailable होने पर user request reject कर सके, agent pending request छोड़ सके और application shutdown live approvals को invalidate करे। Apple LocalAuthentication में user cancellation, application cancellation और system cancellation के बीच अंतर करता है। UI उन्हें सामान्य «canceled» message के नीचे रखे, फिर भी आपके audit model में यह distinction बची रहनी चाहिए।

विश्वसनीय fallback path काम करते समय लगभग उबाऊ लगता है। Screen sensor के बारे में सच बताती है, agent को ऐसा state मिलता है जिसका वह पालन कर सकता है, secrets vault में रहते हैं और laptop lid बंद होने से कोई action बाहर नहीं निकलता। यही standard रखें: हर physical failure एक specific, non-escalating outcome तक पहुंचे।
