Get started

تأییدهای اپراتور در چندین سطح کاربری

تأییدهای اپراتور در چند سطح

این طراحی #103505 را پیگیری می‌کند. این طراحی، اختیار تأیید محلیِ فرایند را با یک چرخهٔ حیات تحت مالکیت Gateway و متکی به SQLite جایگزین می‌کند. هر تأیید اجرای دستور یا Plugin/ابزار تحت مالکیت Gateway، یک شناسهٔ پایدار، یک مسیر احراز هویت‌شده در رابط کنترل، سازوکار اتمی «نخستین پاسخ برنده است» و نگاشت‌هایی مختص اپراتور به جریان‌های نشست مبدأ و نشست‌های بالادستی آن دریافت می‌کند.

کنش‌های درون‌خطی و پیوندهای عمیق در کنار هم وجود دارند. هیچ کلیدی برای تغییر حالت تأیید وجود ندارد.

اهداف

  • یک شیء تأیید پایدار برای دروازه‌های اجرای دستور و Plugin/ابزار.
  • مسیر پایدار ${controlUiBasePath}/approve/{approvalId}.
  • حل‌وفصل از هر رابط کنترل، برنامهٔ بومی یا سطح کانال مجاز.
  • رفتار اتمی «نخستین پاسخ برنده است» در سطح‌های هم‌زمان.
  • تلاش‌های مجدد یکسان، ایدمپوتنت هستند؛ پاسخ‌های دیرهنگامِ متعارض نمی‌توانند پاسخ برنده را بازنویسی کنند.
  • مهلت زمانی، احکام معتبرِ بدشکل، مسیرهای مفقود، لغو و راه‌اندازی مجدد، همگی به‌صورت بسته و امن شکست می‌خورند.
  • رویدادهای درخواست و پایانی به نشست مبدأ و همهٔ مالکان والد/هماهنگ‌کنندهٔ مرتبط می‌رسند.
  • کانال‌ها کنش‌های نوع‌دارِ تأیید و پیمایش را دریافت می‌کنند؛ دادهٔ فراخوانیِ انتقال، خصوصیِ کانال باقی می‌ماند.
  • متدهای موجود Gateway برای اجرای دستور و Plugin سازگار باقی می‌مانند، درحالی‌که پیاده‌سازی آن‌ها به یک سرویس واحد همگرا می‌شود.

اهداف خارج از محدوده

  • پایدارسازی یا ازسرگیری خودِ اجرای مسدودشدهٔ ابزار پس از راه‌اندازی مجدد Gateway.
  • تبدیل شناسه یا نشانی تأیید به اعتبارنامهٔ حامل.
  • افزودن درخواست‌های تأیید به رونوشت‌های قابل‌مشاهده برای مدل یا بیدارکردن عامل‌های والد.
  • انتقال سیاست تأیید، فرمان‌های محصول یا مجوزدهی بازبین به Pluginهای کانال.
  • تکثیر وضعیت تأیید برای هر کانال، دستگاه یا بالادست.
  • بازطراحی فهرست‌های مجاز اجرای دستور، ترکیب سیاست Plugin یا ماندگاری allow-always، مگر در موارد لازم برای رفع ابهام نتایج پایانی.
  • دردسترس‌قراردادن از راه دور یک TUI توکارِ بدون Gateway در گام نخست. این TUI صرفاً محلی باقی می‌ماند و وقتی هیچ بازبینی وجود ندارد، باید به‌صورت بسته و امن شکست بخورد.

خط مبنا و نگاشت شواهد پیش از عرضه

این جدول وضعیت پیاده‌سازی را هنگام بازشدن #103505 ثبت می‌کند. بخش‌های عرضه در ادامه، رجیستری پایدار، کنش‌های نوع‌دار، صفحهٔ پیوند عمیق و گام‌های کلاینت بومی را که بر آن خط مبنا ساخته شده‌اند، پیگیری می‌کنند.

سطح نقطهٔ ورود و مالک در خط مبنا رفتار و شکاف خط مبنا
اجرای عامل src/agents/bash-tools.exec-approval-request.ts، src/agents/bash-tools.exec-host-shared.ts ثبت دومرحله‌ای exec.approval.* از رقابت زودهنگام /approve جلوگیری می‌کند، اما مهلت زمانی همچنان می‌تواند از طریق askFallback به مجازشدن منجر شود.
دروازهٔ ابزار Plugin src/agents/agent-tools.before-tool-call.ts plugin.approval.* را درخواست می‌کند؛ timeoutBehavior: "allow" می‌تواند دروازه‌ای را که مهلتش تمام شده تأیید کند. حالت توکار در src/infra/embedded-plugin-approval-broker.ts اختیار محلیِ فرایند جداگانه‌ای دارد.
دروازهٔ Node در Plugin src/gateway/node-invoke-plugin-policy.ts مستقیماً از طریق مدیر Plugin ایجاد و پخش می‌کند و بخشی از چرخهٔ حیات متد سرور را تکرار می‌کند.
اختیار Gateway src/gateway/server-aux-handlers.ts، src/gateway/exec-approval-manager.ts، src/gateway/server-methods/approval-shared.ts مدیران جداگانهٔ اجرای دستور و Plugin از نگاشت‌های محلیِ فرایند استفاده می‌کنند. ورودی‌های پایانی به‌مدت 15 ثانیه باقی می‌مانند. «نخستین پاسخ برنده است» فقط درون یک فرایند برقرار است.
پروتکل Gateway packages/gateway-protocol/src/schema/exec-approvals.ts، packages/gateway-protocol/src/schema/plugin-approvals.ts، src/gateway/methods/core-descriptors.ts اجرای دستور دارای get فقط برای موارد در انتظار است؛ Plugin فاقد get است؛ هیچ جست‌وجوی پایانیِ مستقل از نوع برای یک پیوند عمیق وجود ندارد.
تحویل src/infra/exec-approval-channel-runtime.ts، src/infra/approval-native-runtime.ts، src/infra/approval-handler-runtime.ts از مسیریابی مبدأ، پیام‌های خصوصی تأییدکننده، بازپخش موارد در انتظار، رسیدگی‌کننده‌های بومی و پاک‌سازی پایانی درون‌فرایندی پشتیبانی می‌کند. یک پیگیری جداگانه، تطبیق پایانی پایدار را می‌افزاید.
کنش‌های قابل‌حمل src/interactive/payload.ts، src/plugin-sdk/interactive-runtime.ts، src/plugin-sdk/approval-reply-runtime.ts دکمه‌های تأیید، کنش‌های فرمانی حاوی /approve ... هستند؛ هدف‌های URL و برنامهٔ وب، فیلدهای دکمهٔ بدون نوع هستند.
Telegram extensions/telegram/src/approval-handler.runtime.ts، extensions/telegram/src/button-types.ts رندرکننده پیش از تولید دادهٔ فراخوانی خصوصی، متن فرمان را برای تشخیص معنای تأیید تجزیه می‌کند.
رابط کنترل ui/src/app/exec-approval.ts، ui/src/app/overlays.ts، ui/src/components/exec-approval.ts رابط تأیید یک پنجرهٔ مودال سراسری است. ui/src/app-route-paths.ts و ui/src/app-routes.ts از مسیرهای دقیق استفاده می‌کنند و مسیرهای ناشناخته را به گفت‌وگو بازنویسی می‌کنند.
مالکیت نشست src/agents/subagent-registry.types.ts، src/agents/subagent-registry-read.ts، src/config/sessions/types.ts مالکیت کنترل‌کننده، درخواست‌کننده، والد صریح و ایجاد قدیمی وجود دارد، اما رویدادهای تأیید به جریان‌های آن نشست‌ها نگاشت نمی‌شوند.
وضعیت مشترک src/state/openclaw-state-schema.sql، src/state/openclaw-state-db.ts تراکنش‌های فوری موجود و به‌روزرسانی‌های شرطی Kysely از مقایسه‌و‌تنظیم پایدار در state/openclaw.sqlite پشتیبانی می‌کنند.

آزمون‌های فعلی نماینده شامل src/gateway/exec-approval-manager.test.ts، src/gateway/server-methods/approval-shared.test.ts، src/agents/bash-tools.exec-gateway-approval.e2e.test.ts، extensions/telegram/src/approval-handler.runtime.test.ts و ui/src/e2e/approval-flow.e2e.test.ts هستند.

SDK مربوط به Plugin همچنان تنها مرز کانال/Plugin است. تغییرات زمان اجرای تأیید و ارائه باید از طریق زیرمسیرهای موجود src/plugin-sdk/approval-*.ts و src/plugin-sdk/interactive-runtime.ts صادر شوند؛ کد تولیدی Plugin نباید اجزای داخلی Gateway را وارد کند.

نمونه‌های پیشین

Omnigent معناشناسی مفیدی برای تجربهٔ کاربری و شکست ارائه می‌دهد:

  • approval.py، ASK را متوقف نگه می‌دارد، مهلت‌های زمانی مختص هر سیاست را اعمال می‌کند و فقط پذیرش دقیق را تأیید تلقی می‌کند.
  • sessions.py، دروازهٔ ابزار بومی سمت سرور و نگاشت درخواست/حل‌وفصل به بالادست را در بر دارد.
  • ApprovePage.tsx، صفحهٔ مستقل تأیید موبایل را فراهم می‌کند.

ادعای ذخیره‌سازی آن را بدون بررسی کپی نکنید. وضعیت فعالِ در انتظار فعلی در _elicitation_registry.py محلیِ فرایند است و جدول بلااستفادهٔ موارد در انتظار توسط e3b1f2a4c9d7_drop_pending_tool_calls_table.py حذف می‌شود. OpenClaw آگاهانه فراتر می‌رود: SQLite مرجع معتبر است و هر گذار پایانی یک مقایسه‌و‌تنظیم پایگاه داده محسوب می‌شود.

معماری و مالکیت

Gateway مالک چرخهٔ حیات است:

  1. یک عامل، قلاب Plugin یا سیاست Node، یک درخواست مختص نوع و اتصال اجرای محلیِ فرایند را ارائه می‌کند.
  2. Gateway آن را اعتبارسنجی می‌کند و یک نگاشت پاک‌سازی‌شده برای بازبین می‌سازد.
  3. سرویس تأیید، مخاطبان مبدأ/مالک را محاسبه می‌کند، ردیف مرجع را درج می‌کند و سپس انتظارگر درون‌فرایندی را ثبت می‌کند.
  4. پس از درج پایدار، Gateway رویدادهای تأیید موجود، نگاشت‌های نشست، اعلان‌های کانال و ارسال بومی را منتشر می‌کند.
  5. هر سطح از طریق همان سرویس حل‌وفصل می‌شود.
  6. سرویس یک گذار پایانی را ثبت می‌کند، انتظارگر زمان اجرا را بیدار می‌کند و نگاشت‌های پایانی را منتشر می‌کند.
  7. شکست در تحویل رویداد هرگز تصمیم ثبت‌شده را بازنمی‌گرداند؛ کلاینت‌ها از طریق approval.get یا بازپخش فهرست بازیابی می‌شوند.

مرزهای مالکیت:

  • src/gateway/: سرویس تأیید، مجوزدهی، آداپتورهای RPC، ساخت URL، چرخهٔ حیات انتظارگر و انتشار رویداد.
  • src/state/: شِمای مشترک و نوع‌های تولیدشدهٔ Kysely.
  • src/infra/: مدل‌های نمایشی پاک‌سازی‌شدهٔ تأیید و ساخت ارائهٔ قابل‌حمل.
  • src/agents/: درخواست، انتظار و اعمال حکم بازگشتی؛ بدون ماندگاری.
  • src/channels/ و extensions/*: رندرکردن کنش‌های نوع‌دار، مجازکردن کاربران کانال، کدگذاری فراخوانی‌های خصوصی و به‌روزرسانی کنترل‌های تحویل‌شده.
  • src/plugin-sdk/: فقط قراردادهای عمومی تأیید و ارائه.
  • ui/: صفحهٔ مستقل و کلاینت‌های موجود صف/پنجرهٔ مودال.

انتظارگر درون‌فرایندی یک سازوکار اعلان است، نه مرجع اختیار. ثبت، ردیف را درج می‌کند و پیش از انتشار درخواست، انتظارگر را به‌صورت هم‌زمان نصب می‌کند؛ بنابراین حل‌کننده نمی‌تواند میان این مراحل وارد شود. هر حل‌کنندهٔ بعدی پیش از خاتمه‌دادن به آن انتظارگر، تغییر را از طریق SQLite ثبت می‌کند.

رکورد پایدار

یک جدول operator_approvals به پایگاه دادهٔ وضعیت مشترک اضافه کنید.

ستون هدف
approval_id شناسهٔ متعارف و یکتای سراسری. شناسه‌های موجود exec و شناسه‌های plugin: را برای سازگاری پروتکل حفظ کنید، اما هرگز نوع را از پیشوند استنباط نکنید.
resolution_ref مکان‌یاب یکتای کامل SHA-256 با کدگذاری base64url برای callbackهای انتقالی که نمی‌توانند شناسهٔ متعارف را حمل کنند. این مجوزدهی یا شناسهٔ URL عمومی نیست.
kind تفکیک‌گر بستهٔ exec | plugin.
status وضعیت بستهٔ pending | allowed | denied | expired | cancelled.
presentation_json نگاشت بازبین اعتبارسنجی‌شده و برچسب‌گذاری‌شده بر اساس نوع. درخواست‌های خام زمان اجرا، اتصال‌های فرمان و payloadهای callback در همان فرایند باقی می‌مانند.
source_agent_id, source_session_key هویت منبع و لنگر نگاشت نشست. کلید نشست ماندگار است؛ UUID چرخشی نشست ماندگار نیست.
audience_session_keys_json آرایهٔ JSON مرتب و بدون تکرار که پیمایش مالکیت سطح‌اولِ محدود آن را تولید می‌کند. رویدادهای درخواست‌شده و پایانی از همین snapshot استفاده می‌کنند.
requested_by_device_id, requested_by_client_id فرادادهٔ ماندگار درخواست‌کننده/ممیزی. شناسهٔ اتصال در حافظه می‌ماند و یک هویت اصلی میان‌سطحی نیست.
reviewer_device_ids_json دستگاه‌های اختیاری بازبین که صراحتاً هدف‌گذاری شده‌اند و فقط زمان اجرای مورد اعتمادِ تأیید آن‌ها را ارائه می‌کند.
runtime_epoch دورهٔ فرایندی که مالک اجرای متوقف‌شده است؛ برای لغو ردیف‌های یتیم پس از راه‌اندازی مجدد استفاده می‌شود.
created_at_ms, expires_at_ms, updated_at_ms زمان‌بندی مرجع.
decision تصمیم صریح کاربر، در صورت وجود.
terminal_reason دلیل بسته، مانند user، timeout، malformed-verdict، no-route، run-aborted یا gateway-restart.
resolved_at_ms, resolver_kind, resolver_id هویت برنده و ممیزی که در سمت سرور نگهداری می‌شود. نگاشت‌های بازبین شناسه‌های خام حل‌کننده را حذف می‌کنند.
consumed_at_ms, consumed_by محافظ بازپخش جداگانه برای allow-once؛ مصرف‌کردن نباید تصمیم ثبت‌شده را پاک کند.

ایندکس‌های الزامی:

ایندکس هدف
(resolution_ref) یکتا ابهام میان‌ستونی approval_id/resolution_ref را هنگام درج رد می‌کند.
(status, expires_at_ms) تأییدهای در انتظار را پیدا و مهلت‌های مرجع را تطبیق می‌دهد.
(source_session_key, created_at_ms DESC) تأییدهای اخیر یک نشست منبع را بازپخش می‌کند.
(resolved_at_ms) تأییدهای پایانی نگهداری‌شده را مطابق سیاست ثابت نگهداری هرس می‌کند.

آرایه‌های مخاطبان کوچک و محدود هستند. بازپخش فیلترشده بر اساس نشست ابتدا ردیف‌های در انتظار و قابل‌مشاهده را از طریق Kysely انتخاب می‌کند، سپس آرایه‌های محدود مخاطبان را در کد برنامه رمزگشایی و فیلتر می‌کند؛ این فرایند از تطبیق رشته‌ای یا پرس‌وجوهای خام JSON در SQL استفاده نمی‌کند.

ردیف‌های پایانی را به‌مدت 30 روز نگه دارید؛ این مدت با نگهداری فرادادهٔ ممیزی در src/audit/audit-event-store.ts هم‌راستا است. هرس‌کردن یک سیاست ثابت نگهداری است، نه یک سطح پیکربندی جدید. پایگاه داده وضعیت خصوصی و محلی صفحهٔ کنترل است، اما APIهای بازبین هرگز نباید کل درخواست ذخیره‌شده یا اتصال زمان اجرا را افشا کنند.

ماشین حالت و مقایسه‌و‌تنظیم

فقط انتقال‌های زیر معتبرند:

  • pending -> allowed: allow-once یا allow-always صریح.
  • pending -> denied: رد صریح، رأی پایانی نامعتبرِ مورد اعتماد، یا نبود مسیر تحویل.
  • pending -> expired: رسیدن به مهلت مرجع.
  • pending -> cancelled: توقف اجرا، خاموش‌شدن کنترل‌شده، یا بازیابی یتیم پس از راه‌اندازی مجدد.

رأی مؤثر هر وضعیت پایانی غیرمجاز، رد است.

حل‌وفصل از یک تراکنش فوری SQLite و به‌روزرسانی شرطی Kysely معادل زیر استفاده می‌کند:

sql
UPDATE operator_approvalsSET status = ?, decision = ?, terminal_reason = ?, resolved_at_ms = ?WHERE approval_id = ?  AND status = 'pending'  AND expires_at_ms > ?;

اگر به‌روزرسانی هیچ ردیفی را تحت تأثیر قرار ندهد، همان تراکنش رکورد را می‌خواند:

  • مفقود یا بدون مجوز: «یافت نشد» برگردانید؛ وجود آن را افشا نکنید.
  • هنوز در انتظار، اما مهلت رسیده است: با مقایسه‌و‌تنظیم آن را به expired تغییر دهید، سپس همان ردیف پایانی را برگردانید.
  • همان تصمیم ثبت‌شده: موفقیت هم‌توان را همراه با برندهٔ ثبت‌شده برگردانید.
  • تصمیم متفاوت: API یکپارچه applied: false را همراه با برندهٔ ثبت‌شده برمی‌گرداند؛ آداپتورهای قدیمی در مواردی که قرارداد منتشرشده‌شان ایجاب می‌کند، APPROVAL_ALREADY_RESOLVED را حفظ می‌کنند.
  • هر وضعیت پایانی: هرگز آن را تغییر ندهید.

now == expires_at_ms منقضی شده است. زمان Gateway مرجع است.

اجرای allow-once از یک CAS دوم روی consumed_at_ms IS NULL استفاده می‌کند که به بافت دقیق موجودِ فرمان/اجرای سیستم متصل است. ردیف تأیید پس از مصرف، به‌عنوان رکورد ممیزی باقی می‌ماند.

ورودی نامعتبر HTTP/RPC که قابل احراز هویت نیست یا نمی‌تواند یک تأیید را شناسایی کند، بدون تغییر رد می‌شود و هرگز نمی‌تواند تأیید کند. رأی پایانی نامعتبری که از یک harness/waiter مورد اعتماد برای تأییدی شناخته‌شده دریافت شود، به denied منتقل می‌شود.

API Gateway

روش‌های بازبین مستقل از نوع را اضافه کنید:

روش قرارداد
approval.get { id } یک نگاشت پایانیِ در انتظار و قابل‌مشاهده، یا نگهداری‌شده را برمی‌گرداند.
approval.resolve { id, kind, decision } شناسهٔ متعارف یا ارجاع انتقالی با اندازهٔ ثابت را می‌پذیرد، سپس مجوزدهی، اعتبارسنجی نوع و تصمیم مجاز، تطبیق مهلت و CAS پایانی را اجرا می‌کند. پاسخ همیشه شناسهٔ متعارف را در بر دارد.

پس از CAS موفق، نگاشت commit‌شده را فوراً برگردانید. رویدادهای قدیمی، انتقال‌دهنده‌های کانال و پایانی‌کننده‌های push، پیگیری‌های مبتنی بر بیشترین تلاش هستند؛ یک سطح کند یا ناموفق نباید پاسخ برنده را به تأخیر بیندازد یا آن را rollback کند.

اعتبارسنجی درخواست مختص نوع در exec.approval.request و plugin.approval.request باقی می‌ماند. exec.approval.get/list/waitDecision/resolve و plugin.approval.list/waitDecision/resolve موجود، چون API منتشرشدهٔ Gateway هستند، به آداپتورهای مرز پروتکل برای سرویس متعارف تبدیل می‌شوند. فراخواننده‌های داخلی در همان تغییر به سرویس مهاجرت می‌کنند.

نگاشت بازبین یک اجتماع تفکیک‌شده است:

ts
type OperatorApproval = {  id: string;  status: OperatorApprovalStatus;  presentation:    | { kind: "exec"; commandText: string /* پیش‌نمایش امن exec */ }    | { kind: "plugin"; title: string; description: string /* پیش‌نمایش امن plugin */ };  // فیلدهای مشترک چرخهٔ عمر};

مسیر پایدار مشتق می‌شود و ذخیره نمی‌شود. approval.get مقدار urlPath را برمی‌گرداند؛ سطح‌هایی که از یک مبدأ عمومی تأییدشده آگاه‌اند، ممکن است یک url مطلق نیز دریافت کنند. snapshotهای بازبین کلیدهای نشست منبع و مخاطب را حذف می‌کنند. Gateway این کلیدهای مسیریابی را برای نگاشت جداگانهٔ session.approval در سمت سرور نگه می‌دارد.

رویدادها و کنش‌های قابل‌حمل

PR 1 نام‌ها و payloadهای رویداد منتشرشده و فیلترهای موجود گیرندگان در سطح رکورد را حفظ می‌کند:

  • exec.approval.requested
  • exec.approval.resolved
  • plugin.approval.requested
  • plugin.approval.resolved

این رویدادهای قدیمی می‌توانند شامل کل درخواست زمان اجرا باشند، بنابراین نباید برای همهٔ کلاینت‌های محدود به تأیید منتشر شوند. PR 5 فیلدهای برچسب‌گذاری‌شدهٔ چرخهٔ عمر (status، sourceSessionKey، urlPath، فرادادهٔ پایانی و یک kind در سطح ارائه) را از طریق نگاشت پاک‌سازی‌شدهٔ چرخهٔ عمر اضافه می‌کند، نه با گسترش تحویل رویدادهای قدیمی.

یک رویداد نگاشت session.approval محدود به تأیید اضافه کنید. رویداد متعارف را یک‌بار با کلیدهای ذخیره‌شدهٔ مخاطبان منتشر کنید؛ مشترکان نشست دقیق، همان رویداد را برای هر کلید منطبق دریافت می‌کنند:

  • sessionKey: جریانی که نگاشت را دریافت می‌کند.
  • sourceSessionKey: فرزند/منبعی که مانع را ایجاد کرده است.
  • phase: pending \| terminal که بر اساس وضعیت تأیید تفکیک شده است.
  • یک نگاشت امن OperatorApproval.

کلاینت‌ها با sessions.messages.subscribe { key, agentId?, includeApprovals: true } اعلام مشارکت می‌کنند. پاسخ موفق یک approvalReplay اضافه می‌کند که حداکثر 1,000 تأیید جاری در انتظار برای همان کلید دقیق جریان را در بر می‌گیرد؛ تأییدهایی که کلاینت مشترک نیز در سطح رکورد مجاز به بازبینی آن‌ها است. truncated: false بازپخش فیلترشده را مرجع می‌کند و کلاینت‌های در حال اتصال مجدد، مجموعهٔ محلی موارد در انتظار خود را با آن جایگزین می‌کنند؛ truncated: true سیگنال اضافه‌بار است و کلاینت‌ها باید ورودی‌های محلی دیده‌نشده را تا زمانی که lookup متعارف یا رویدادهای بعدی چرخهٔ عمر آن‌ها را تعیین تکلیف کنند، نگه دارند. timeout ماندگاری که بعداً هنگام بازپخش کشف شود، پیش از بازگرداندن snapshot جدید، tombstoneهای پایانی را فقط برای مخاطبان مشترک و مجاز در سطح رکورد منتشر می‌کند. operator.admin می‌تواند مستقیماً اعلام مشارکت کند؛ کلاینت‌های محدودتر هم به هویت دستگاه جفت‌شده و هم به operator.approvals نیاز دارند. اشتراک نشست به‌تنهایی هرگز امکان مشاهدهٔ تأیید را اعطا نمی‌کند.

رویداد را زیر operator.approvals در src/gateway/server-broadcast.ts ثبت کنید. نگاشت مشاهده‌ای است: هرگز ردیف‌های transcript را اضافه نمی‌کند، sessions.changed منتشر نمی‌کند یا یک عامل را بیدار نمی‌کند.

MessagePresentationAction را در src/interactive/payload.ts گسترش دهید:

ts
type MessagePresentationAction =  | { type: "command"; command: string }  | { type: "callback"; value: string }  | {      type: "approval";      approvalId: string;      approvalKind: "exec" | "plugin";      decision: ExecApprovalDecision;    }  | { type: "url"; url: string }  | { type: "web-app"; url: string };

هسته، کنش‌های تصمیم‌گیری نوع‌دار و، در صورت در دسترس بودن مبدأ مطلق و تأییدشدهٔ Control UI، یک پیوند جداگانهٔ بازبینی می‌سازد. کانال‌ها یک کنش تأیید را در قالب فراخوان برگشتی خود کدگذاری می‌کنند و نتیجه را به سرویس مرجع می‌فرستند. فراخوان برگشتی، در صورت گنجیدن شناسهٔ مرجع دقیق، از همان استفاده می‌کند؛ در غیر این صورت، از resolution_ref منحصربه‌فردِ دارای چکیدهٔ کاملِ ردیف استفاده می‌کند. مرجع فقط یک کلید فشرده برای جست‌وجو است: احراز هویت عادی Gateway، مجوزدهی رکورد، نوع صریح، اعتبارسنجی تصمیم مجاز، تطبیق مهلت و CAS نخستین پاسخ همچنان اعمال می‌شوند. کانال‌ها نباید شناسه‌ها را کوتاه کنند، پیشوندهای هش را تفکیک کنند، متن /approve را تجزیه کنند یا نوع را از پیشوند شناسه استنباط کنند.

button.url، button.webApp و کنترل‌های تأیید مبتنی بر فرمان را به‌عنوان ورودی‌های منسوخِ سازگاری SDK افزونه نگه دارید. آن‌ها را در مرز SDK عادی‌سازی کنید؛ همهٔ فراخوانندگان داخلیِ همراه را در همان PR مهاجرت دهید. /approve {id} {decision} همچنان یک جایگزین متنی و فرمان CLI/گفت‌وگو است، نه قرارداد معنایی دکمه.

Control UI

مسیر ${basePath}/approve/{approvalId} است. شناسه تنها پارامتر مسیر است؛ هویت نشست مبدأ از رکورد می‌آید.

از آنجا که مسیریاب کنونی مسیرهای ایستای دقیق دارد و مسیرهای ناشناخته را به گفت‌وگو بازنویسی می‌کند، این پیوند عمیق را پیش از عادی‌سازی معمول مسیر در ui/src/app/bootstrap.ts شناسایی کنید. از راه‌اندازی معمول Gateway/احراز هویت دوباره استفاده کنید، اما صفحهٔ مستقل تأیید را بیرون از پوستهٔ نوار کناری و پنجرهٔ سراسری نمایش دهید.

سند متعلق به Gatewayای است که URL آن را ارائه کرده است. اتصال اولیهٔ آن، انتخاب ماندگار Gateway راه‌دور در برنامهٔ کامل را نادیده می‌گیرد، بدون آنکه تنظیمات آن انتخاب را تغییر دهد یا کپی کند؛ فقط احراز هویت در سطح نشست به Gateway ارائه‌دهنده محدود می‌ماند. احراز هویت بومیِ مورد اعتماد یا یک جایگزین gatewayUrl که جداگانه تأیید شده باشد می‌تواند آن را به مقصد دیگری هدایت کند. هسته، فضای نام تک‌بخشی /approve را پیش از مسیرهای HTTP افزونه و تشخیص افزونهٔ ایستا رزرو می‌کند؛ این شامل شناسه‌هایی نیز می‌شود که به .json یا .js ختم می‌شوند. وقتی ارائهٔ Control UI غیرفعال است، مسیر رزروشده با 404 به‌صورت بسته شکست می‌خورد. صفحه را در بستهٔ اصلی Control UI نگه دارید تا شکست یک قطعهٔ بارگذاری تنبل، تصمیم امنیتی را روی نشانگر بارگذاری معطل نگذارد.

حالت‌های صفحه:

  • در حال بارگذاری
  • احراز هویت لازم است
  • در انتظار
  • در حال تعیین نتیجه
  • در اینجا تأیید یا رد شد
  • در جای دیگری تعیین نتیجه شد
  • منقضی شد
  • لغو شد
  • ممنوع/یافت نشد
  • خطای اتصال با امکان تلاش مجدد

صفحه RPC مربوط به Gateway را فراخوانی می‌کند، نه یک API دوم REST بدون احراز هویت. تازه‌سازی مرورگر، وضعیت ماندگار را دوباره می‌خواند. صفحه هرگز اطلاعات ورود Gateway را در URL، پرس‌وجو یا قطعه قرار نمی‌دهد.

مجوزدهی و حریم خصوصی

URL یک مکان‌یاب است، نه مجوز. تعیین نتیجه نیازمند موارد زیر است:

  1. اتصال احراز هویت‌شدهٔ Gateway؛
  2. operator.approvals یا operator.admin؛
  3. مجوز بازبین در سطح رکورد.

قواعد سطح رکورد:

  • operator.admin می‌تواند بازبینی کند.
  • در صورت وجود، reviewer_device_ids مرجع نهایی است. فقط دستگاه جفت‌شدهٔ operator.approvals که در فهرست آمده باشد می‌تواند بازبینی کند؛ دستگاه درخواست‌کننده دسترسی ضمنی ندارد، مگر آنکه خودش نیز در فهرست باشد.
  • بدون فهرست صریح بازبینان، دستگاه جفت‌شدهٔ درخواست‌کنندهٔ operator.approvals می‌تواند رکورد خودش را بازبینی کند.
  • رکوردهای واقعاً قدیمی که هیچ پیوندی به درخواست‌کننده یا بازبین ندارند، قابلیت مشاهدهٔ گسترده برای دستگاه‌های جفت‌شده را حفظ می‌کنند تا ارتقا، کارهای از پیش در انتظار را معطل نگذارد.
  • محیط‌های اجرای داخلیِ بدون دستگاه می‌توانند از طریق اتصال محدودِ محیط اجرای تأیید، نتیجه را تعیین کنند، اما نمی‌توانند بخوانند. این اختیار فقط از توکن محیط اجرای احراز هویت‌شده توسط سرور می‌آید؛ فیلدهای عمومی approval.resolve نمی‌توانند آن را ایجاد کنند.
  • مالکیت اتصال زندهٔ درخواست‌کننده برای آداپتورهای قدیمی همچنان معتبر است؛ این مالکیت هرگز از تطابق نام کارخواه استنباط نمی‌شود.
  • عضویت در مخاطبان فقط نحوهٔ ارائه را تغییر می‌دهد و هرگز مجوز را گسترش نمی‌دهد.

approval.get فقط نمای پاک‌سازی‌شدهٔ بازبین را ارائه می‌کند و کلیدهای داخلی مسیریابی مبدأ/مخاطبان را حذف می‌کند. رویداد session.approval در PR 5، یک مقصد sessionKey خود را به‌همراه sourceSessionKey حمل می‌کند، پس از آنکه Gateway تصویر لحظه‌ای ماندگار مخاطبان را در سمت سرور اعمال کرد. رویدادهای موجود exec/افزونه تا زمان مهاجرت مصرف‌کنندگان، محمولهٔ تاریخی و گیرندگان محدود خود را حفظ می‌کنند. درخواست اجرایی، پیوند فرمان و ادامه فقط در منتظرشوندهٔ محلیِ فرایند باقی می‌مانند. ردیف ماندگار شامل ارائهٔ امن به‌همراه فرادادهٔ چرخهٔ عمر، مسیریابی و حسابرسی است؛ این ردیف هرگز مقادیر خام محیط، اطلاعات ورود، سرآیندهای احراز هویت یا دادهٔ فراخوان برگشتی کانال را ذخیره نمی‌کند.

نگاشت مخاطبان

مخاطبان را یک‌بار پیش از درج محاسبه کنید و تصویر لحظه‌ای مرتب‌شده را به‌صورت ماندگار ذخیره کنید. مالکیت یک گراف است و همیشه زنجیره‌ای با یک والد نیست: یک فرزند ممکن است هم کنترل‌کنندهٔ فعلی و هم درخواست‌کنندهٔ اصلی داشته باشد و این مالکان می‌توانند به ریشه‌های متفاوتی منتهی شوند.

از یک پیمایش سطح‌اول قطعی استفاده کنید:

  1. صف را با کلید نشست مبدأ مقداردهی اولیه کنید.
  2. برای هر کلید خارج‌شده از صف، جدیدترین ردیف رجیستری زیرعامل را بخوانید و هر دو یال مالکیت متمایز را با ترتیب ثابت وارد صف کنید: ابتدا controllerSessionKey، سپس requesterSessionKey.
  3. وقتی یک ردیف رجیستری قابل استفاده وجود دارد، تبار ورودی نشست را که ممکن است پس از هدایت منسوخ شده باشد نیز دنبال نکنید. در غیر این صورت، یال جایگزین فعلی و یگانهٔ parentSessionKey ?? spawnedBy را وارد صف کنید.
  4. هنگام ورود به صف، عادی‌سازی و موارد تکراری را حذف کنید تا نخستین و کوتاه‌ترین مسیر برنده شود.
  5. در 64 کلید منحصربه‌فرد متوقف شوید؛ این سقف اندازهٔ مخاطبان، عمق پیمایش را نیز محدود می‌کند.

منبع رجیستری src/agents/subagent-registry-read.ts است؛ فیلدهای مالکیت در src/agents/subagent-registry.types.ts تعریف شده‌اند. فیلدهای جایگزین نشست در src/config/sessions/types.ts تعریف شده‌اند.

نگاشت‌های درخواست‌شده و پایانی از همان مخاطبان ماندگار استفاده می‌کنند، حتی اگر مالکیت تمرکز/کنترل‌کننده در زمان انتظار تأیید تغییر کند. این امر پاک‌سازی پایانی را برای هر جریان نشست مخاطبانی که نگاشت درخواست را دریافت کرده است تضمین می‌کند. تعیین نتیجه همیشه شناسهٔ تأیید مبدأ را هدف می‌گیرد؛ نشست‌های مخاطبان هرگز وضعیت تأیید شبیه‌سازی‌شده دریافت نمی‌کنند. پاک‌سازی پیام کانالِ بازفرستاده‌شده همچنان پیگیری جداگانهٔ مکان‌یاب تحویل در ادامه است.

صرفاً برای یک تأیید، پیام رونوشت ننویسید، اعلان سیستمی تزریق نکنید، نوبت‌های مالک را آغاز نکنید یا sessions.changed منتشر نکنید.

همگرایی سطح تحویل‌شده

کنترل‌کننده‌های بومی تأیید از قبل ورودی‌های پیام تحویل‌شدهٔ خود را به‌اندازهٔ کافی نگه می‌دارند تا کنترل‌های فعال را جایگزین یا بازنشسته کنند. پیام‌های عمومی تأیید بازفرستاده‌شده در حال حاضر MessageReceipt را دور می‌اندازند، بنابراین تصمیم‌گیری در سطحی دیگر می‌تواند باعث شود کنترل‌های قدیمی آن‌ها همچنان در انتظار به نظر برسند. یک پیگیری جداگانه این شکاف را با جدول فرزند operator_approval_deliveries در پایگاه دادهٔ وضعیت مشترک می‌بندد.

هر ردیف، شناسهٔ تأیید، یک شناسهٔ تحویل منحصربه‌فرد، کانال/حساب/مسیر دقیق، یک مکان‌یاب پیام خصوصیِ کانال با اندازهٔ محدود و اعتبارسنجی‌شده با JSON، زمان‌های تحویل و وضعیت نهایی‌سازی را ذخیره می‌کند. این ردیف هرگز دادهٔ فراخوان برگشتی، توکن‌های تصمیم یا درخواست‌های خام تأیید را ذخیره نمی‌کند. کانال مالک کدگذاری مکان‌یاب و تغییر پیام است؛ هسته مالک وضعیت مرجع، انتخاب هدف، سیاست تلاش مجدد و متن پایانی جایگزین است.

ثبت تحویل و تعیین نتیجهٔ پایانی به‌صورت ایمن با یکدیگر رقابت می‌کنند:

  1. پس از آنکه ارسال در انتظار رسید خود را برگرداند، مکان‌یاب تحویل را درج و وضعیت تأیید والد را در یک تراکنش بخوانید.
  2. اگر والد از قبل پایانی است، به‌جای رها کردن تحویل دیرهنگام در حالت انتظار، نهایی‌سازی فوری را زمان‌بندی کنید.
  3. هر گذار پایانیِ ثبت‌شده، همهٔ ردیف‌های تحویل نهایی‌نشده را جداگانه زمان‌بندی می‌کند؛ پخش‌های قابل حذف آغازگر نیستند.
  4. نهایی‌ساز کانال، replaced، retired یا unsupported را گزارش می‌دهد. جایگزینی، پیام پایانی تکراری را سرکوب می‌کند؛ بازنشستگی، پیگیری پایانی موجود را می‌فرستد؛ پشتیبانی‌نشدن یا شکست، بدون بازگرداندن CAS تأیید، به جایگزین برمی‌گردد.
  5. راه‌اندازی، تأییدهای پایانی دارای تحویل‌های ناتمام را دوباره امتحان می‌کند و پاک‌سازی را در برابر راه‌اندازی مجدد Gateway مقاوم می‌سازد.

این چرخهٔ عمر انتقال، یک هوک اختیاری آداپتور تحویل است، نه یک رندرکننده یا کنش پیام روبه‌روی مدل. پیام‌های C2C/گروهی QQ در حال حاضر هیچ API برای ویرایش، حذف یا پاک‌کردن صفحه‌کلید ندارند؛ این آداپتور همچنان پشتیبانی‌نشده باقی می‌ماند و تا زمانی که انتقال به API تغییر دست یابد، فقط می‌تواند پس از یک کلیک بعدی حقیقت مرجع را نمایش دهد.

معنای راه‌اندازی مجدد، مهلت و مسیر

ماندگاری SQLite به‌معنای ازسرگیری اجرا نیست. پیوندهای فرمان/ابزار در حافظه باقی می‌مانند، زیرا می‌توانند شامل واقعیت‌های حساس امنیتیِ محیط اجرا باشند و قرارداد یک کار قابل ازسرگیری نیستند.

هنگام راه‌اندازی Gateway:

  • یک دورهٔ جدید محیط اجرا ایجاد کنید؛
  • ردیف‌های در انتظار از دوره‌های قدیمی‌تر را به‌صورت اتمی و با دلیل gateway-restart به cancelled منتقل کنید؛
  • ردیف‌ها را نگه دارید تا URLهایشان توضیح دهند چه اتفاقی افتاده است؛
  • هرگز تأیید بعدی را در برابر پیوند محیط اجرای ازدست‌رفته اجرا نکنید.

زمان‌سنج‌ها بهینه‌سازی‌هایی برای بیدارسازی هستند. مرجع مهلت در expires_at_ms ذخیره می‌شود؛ خواندن‌ها، انتظارها و تعیین نتایج همگی تطبیق انقضا را اجرا می‌کنند.

رفتار سخت‌گیرانهٔ نهایی:

  • پایان مهلت -> expired، رد؛
  • نبود مسیر -> denied، رد؛
  • توقف اجرا -> cancelled، رد؛
  • رأی مورد اعتمادِ بدشکل -> denied، رد؛
  • فقط یک تصمیم صریح و مجاز برای اجازه -> allowed.

رفتار exec منتشرشدهٔ کنونی هنوز با این قرارداد تعارض دارد:

  • src/agents/bash-tools.exec-host-shared.ts ممکن است askFallback را اعمال کند.
  • docs/tools/exec-approvals.md و docs/cli/approvals.md آن سطح را مستند می‌کنند.

تأییدهای افزونه اکنون هنگام پایان مهلت و رأی‌های بدشکل به‌صورت بسته شکست می‌خورند؛ فیلد قدیمی timeoutBehavior همچنان پذیرفته می‌شود، اما نادیده گرفته می‌شود. پیگیری معنای سخت‌گیرانهٔ exec باید کد، نوع‌ها، مستندات، آزمون‌ها و تغییرنامه را با هم و با بازبینی صریح مالک/امنیت به‌روزرسانی کند. askFallback می‌تواند در طول مهاجرت همچنان انتخاب سیاست پیش از دروازه را توصیف کند، اما نباید پایان مهلت یک رکورد در انتظارِ ایجادشده را به تأیید تبدیل کند.

برنامهٔ سازگاری

  • پروتکل افزایشی Gateway؛ بدون افزایش نسخهٔ پروتکل.
  • روش‌ها و رویدادهای موجود exec/افزونه را در مرز خارجی حفظ کنید.
  • شناسه‌های موجود، از جمله پیشوندهای plugin:، را نگه دارید، اما استفاده از پیشوندها به‌عنوان اطلاعات نوع را متوقف کنید.
  • رفتار فرمان متنی /approve را نگه دارید.
  • فیلدهای قدیمی URL دکمه/Web App و کنش‌های فرمان را به‌عنوان ورودی سازگاری SDK افزونه نگه دارید؛ خروجی جدید هسته نوع‌دار است.
  • همهٔ کانال‌های همراه و فراخوانندگان داخلی را در همان تغییر کنش نوع‌دار مهاجرت دهید.
  • یک ورودی تغییرنامه برای URL/صفحهٔ جدید و تغییر بعدی رفتار پایان مهلت اضافه کنید.
  • تنظیم حالت درخواست اطلاعات اضافه نکنید.

عرضه

PR 1: چرخهٔ عمر ماندگار

  • این یادداشت طراحی.
  • طرح‌وارهٔ مشترک SQLite، تولید Kysely، مخزن و هرس 30روزه.
  • سرویس تأیید Gateway، پل منتظرشوندهٔ محیط اجرا و مدیریت موارد یتیم پس از راه‌اندازی مجدد.
  • approval.get/resolve یکپارچه.
  • آداپتورهای روش exec/افزونه.
  • آزمون‌های برنده‌شدن نخستین پاسخ، توان تکرار بدون تغییر نتیجه، انقضا، مجوزدهی و مصرف.
  • هنوز هیچ تغییری در رفتار UI یا کانال ایجاد نمی‌شود.

PR 2: کنش‌های نوع‌دار و فراخوان‌های برگشتی کانال

  • کنش‌های تأیید، URL و Web App دارای نوع مشخص.
  • سازنده‌های اصلی ارائه و خروجی‌های SDK افزونه.
  • کدگذاری callback خصوصیِ انتقال با نوع مالک صریح.
  • ارجاع‌های callback پایدار با اندازه ثابت برای شناسه‌های متعارفی که از محدودیت‌های انتقال فراتر می‌روند.
  • مهاجرت کانال‌های همراه از استنتاج متن فرمان و شناسه تأیید.
  • حقیقت متعارف نخستین پاسخ در سطح کلیک‌شده و به‌روزرسانی‌های نهایی فعالِ بومی بر مبنای بهترین تلاش؛ نهایی‌سازی پایدار پیام کانال همچنان کاری برای پیگیری است.
  • آزمون‌های SDK و کانال‌های همراه.

PR 3: پیوند عمیق رابط کاربری کنترل

  • صفحه مستقل و احرازهویت‌شده تأیید و مسیریابی راه‌اندازی آگاه از مسیر پایه.
  • اتصال به Gateway سرویس‌دهنده بدون تغییر انتخاب راه‌دور ذخیره‌شده اپراتور.
  • فضای نام HTTP تأیید تحت مالکیت هسته، شامل شناسه‌های مشابه دارایی.
  • بار URL ساخته‌شده توسط Gateway و نظرسنجی وضعیت در انتظار تا زمان ارائه رویدادهای چرخه‌عمر.
  • اثبات عرض موبایل، اتصال مجدد، پاسخ رقیب، بارگذاری مجدد و مسیر نصب‌شده.

PR 4: کلاینت‌های بومی

  • سطوح بازبینی iOS و Android از approval.get/resolve آگاه از نوع استفاده می‌کنند؛ watchOS اعلان‌ها و تصمیم‌های امن برای بازبین را از طریق iPhone جفت‌شده منتقل می‌کند.
  • Watch تصمیم‌های اجرایی پشتیبانی‌شده در قرارداد انتقال فشرده خود را ارائه می‌دهد: یک‌بار اجازه‌دادن و ردکردن.
  • حقیقت نهایی متعارف نخستین پاسخ جایگزین وضعیت محلی تصمیمِ تلاش‌شده می‌شود.
  • تأییدیه‌های گم‌شده یا مبهمِ رفع، کنترل‌ها را تا بازخوانی متعارف منجمد می‌کنند.
  • نمونه‌های قبلاً منتشرشده Gateway v4 بازبینی اجرا را از طریق یک جایگزین محدودِ روش قدیمی حفظ می‌کنند؛ حفظ وضعیت نهایی میان‌سطحی به روش‌های یکپارچه نیاز دارد.
  • هشدارهای بازبین و زمینه مالک در iPhone، Watch و Android قابل‌مشاهده می‌مانند.
  • اثبات واحد، ساخت و پلتفرم بومی.

PR 5: انتشار چرخه‌عمر به نیاکان

  • تحویل در انتظار/نهایی session.approval از تصویر لحظه‌ای مخاطبان که در PR 1 ماندگار شده است.
  • اشتراک دقیق نشست، بازپخش هنگام اتصال مجدد و سنگ‌قبرهای نهایی بدون تغییر رونوشت یا بیدارکردن عامل.
  • callbackهای چرخه‌عمر پس از درج پایدار/CAS اجرا می‌شوند و هرگز به مرجع تأیید تبدیل نمی‌شوند.
  • اثبات زیرعامل تودرتو و اتصال مجدد.

PR 6: رفتار بسته در هنگام شکست

  • node-invoke-plugin-policy.ts و کارگزار افزونه تعبیه‌شده را از مرجع تکراری مهاجرت دهید.
  • معناشناسی سخت‌گیرانه مهلت زمانی، ورودی بدشکل، نبود مسیر، اتصال و مصرف یک‌بار اجازه‌دادن.
  • تنظیمات منتشرشده سهل‌گیرانه مهلت زمانی را منسوخ کنید، بدون آنکه پس از در انتظار قرارگرفتن یک درخواست رعایت شوند.
  • اثبات رقابت چندسطحی و تزریق شکست.

پیگیری: پاک‌سازی پایدار پیام راه‌دور

  • مکان‌یاب‌های تحویلِ ارسال‌شده را ماندگار کنید و پس از راه‌اندازی مجدد، هر پیام کانال تحویل‌شده را نهایی کنید.
  • این چرخه‌عمر انتقال را از مرجع متعارف تأیید و کنش‌های ارائه دارای نوع جدا نگه دارید.

آزمون‌ها

پوشش متمرکز الزامی:

  • بازگشایی SQLite نگاشت‌های در انتظار و نهایی را حفظ می‌کند.
  • دو رفع‌کننده هم‌زمان دقیقاً یک برنده CAS ایجاد می‌کنند.
  • تلاش مجدد با همان تصمیم به‌صورت هم‌توان موفق می‌شود؛ تلاش مجدد متعارض برنده ثبت‌شده را بازمی‌گرداند.
  • رفع در مهلت یا پس از آن نمی‌تواند تأیید کند.
  • allow-once دقیقاً یک‌بار قابل‌مصرف است، بدون پاک‌کردن وضعیت ممیزی نهایی.
  • راه‌اندازی، دوره‌های اجرایی قدیمی‌تر را لغو می‌کند.
  • جست‌وجو و رفع غیرمجاز، وجود رکورد را افشا نمی‌کنند.
  • فهرست مجاز صریح بازبین و رفتار عمومی operator.approvals جفت‌شده.
  • روش‌های قدیمی اجرا و افزونه از یک مخزن مشترک استفاده می‌کنند.
  • طرحواره‌های درخواست/فهرست/دریافت/رفع Gateway و بارهای رویداد افزایشی.
  • عادی‌سازی کنش دارای نوع، رندر جایگزین، خروجی‌های SDK و تغییر وضعیت کانال‌های همراه.
  • کدگذاری callback در Telegram شامل داده‌های خصوصیِ انتقال است و هیچ استنتاج رشته فرمانی ندارد.
  • فرزند مستقیم، مالکان کنترل‌کننده/درخواست‌کننده منشعب، مالکان تودرتو، واگذاری مجدد، جایگزین فیلد نشست، چرخه و سقف اندازه مخاطبان.
  • آرایه‌های مخاطبان درخواست‌شده و نهایی یکسان هستند.
  • نگاشت‌های مالک هیچ تغییر رونوشت یا بیدارشدن عاملی ایجاد نمی‌کنند.
  • مسیر رابط کاربری کنترل در / و یک مسیر پایه پیکربندی‌شده کار می‌کند؛ تازه‌سازی، حقیقت در انتظار یا نهایی را نشان می‌دهد.
  • پاسخ‌های هم‌زمان رابط کاربری کنترل و Telegram یک برنده و پیام «در جای دیگری رفع شد» را برای بازنده نشان می‌دهند.
  • شناسه‌های تأیید بومی و شناسه‌های مالک Gateway، بایت‌های دقیق UTF-8 را در سراسر مسیریابی و تطبیق حفظ می‌کنند.
  • مذاکره خانواده RPC بومی برای هر مسیر پذیرفته‌شده Gateway یک خانواده متعارف یا قدیمی را تثبیت می‌کند و پس از استفاده هرگز بی‌سروصدا تنزل نمی‌دهد.
  • تأییدیه‌های گم‌شده رفع بومی، کنش‌ها را تا بازخوانی متعارف منجمد می‌کنند؛ بازخوانی ناموفق نمی‌تواند برنده‌ای جعل کند یا تازه‌سازی Watch را تأیید کند.
  • هم‌بستگی درخواست تصویر لحظه‌ای Watch تنها برای مالک دقیق Gateway جفت‌شده و یک بازخوانی متعارف تکمیل‌شده در iPhone پذیرفته می‌شود.
  • اثبات مسیر کاربر از طریق Testbox/Crabbox، شامل صفحه تأیید با عرض موبایل، پاک‌سازی کنش Telegram و یک رفت‌وبرگشت در انتظار/رفع/بازنده دیرهنگام میان Android، iPhone و Watch.

مشاهده‌پذیری

گزارش‌های ساخت‌یافته و بدون محتوا از گذارها را با شناسه تأیید، نوع، کلید نشست مبدأ، وضعیت، دلیل و تأخیر منتشر کنید. هرگز پیش‌نمایش یا اتصال خام را ثبت نکنید.

ردیابی موارد زیر:

  • تعداد درخواست‌شده بر اساس نوع؛
  • تعداد نهایی بر اساس نوع/وضعیت/دلیل؛
  • سنجش در انتظار؛
  • تأخیر از درخواست تا نهایی؛
  • نتایج رقابت رفع: برنده، تلاش مجدد هم‌توان، تعارض، منقضی‌شده؛
  • تعداد مسیرهای تحویل و ردهای ناشی از نبود مسیر؛
  • لغو موارد یتیم هنگام راه‌اندازی؛
  • اندازه مخاطبان.

یک گذار ثبت‌شده موفق محسوب می‌شود، حتی اگر تحویل بعدی رویداد شکست بخورد. مشترکان چرخه‌عمر از طریق بازپخش PR 5 و جست‌وجوی متعارف بازیابی می‌شوند. نهایی‌سازی پایدار پیام کانال همچنان همان پیگیری جداگانه بالاست.

تصمیم‌های باز

  1. مبدأ رابط کاربری کنترل قابل‌دسترسی از بیرون. هر تصویر لحظه‌ای شامل urlPath نسبی و پایدار است. یک URL مطلق تنها پس از موفقیت در معرض‌گذاری Gateway می‌تواند از مکان ذخیره‌شده Tailscale Serve/Funnel اعلام شود؛ allowedOrigins، سرآیندهای Host درخواست، gateway.remote.url و گزینه‌های loopback/LAN صرفاً نمایشی، مبدأهای متعارف نیستند. Telegram می‌تواند از پوسته Mini App احرازهویت‌شده خود استفاده کند تا مسیر تأیید را در جریان راه‌اندازی اولیه حفظ کند. پراکسی‌های معکوس دلخواه تا زمانی که یک قرارداد صریح URL عمومی به‌طور جداگانه بازبینی نشده باشد، فقط نسبی می‌مانند. هرگز اجازه ندهید یک کانال مبدأ را حدس بزند.
  2. گذار سازگاری مهلت زمانی سخت‌گیرانه اجرا. مهلت‌های زمانی تأیید افزونه اکنون به‌صورت بسته شکست می‌خورند و timeoutBehavior منسوخ شده است. قرارداد منتشرشده باقی‌مانده askFallback پیش از آنکه پس از پایان مهلت یک درخواست در انتظار، مجوز اجرا را متوقف کند، به بازبینی صریح مالک/امنیت، گزارش تغییرات، مستندات و تصمیم مهاجرت/منسوخ‌سازی نیاز دارد.
  3. حالت تعبیه‌شده بدون Gateway. پیشنهاد: در ابتدا آن را فقط محلی نگه دارید، سپس هنگامی که Gateway وجود دارد، آن را به کلاینت سرویس متعارف تبدیل کنید. پیوند عمیقی را که هیچ سروری قادر به رفع آن نیست اعلام نکنید.
Was this useful?
On this page

On this page