وثائق بوابة القرار

تقييم بوابة حتمي وقابل لإعادة التشغيل مع قرارات قابلة للتدقيق.

وثائق Asset Core

البدء مع بوابة القرار

نظرة سريعة

ما: تشغيل سيناريو بوابة القرار بشكل محلي لماذا: رؤية دورة الحياة الكاملة: تعريف -> بدء -> تقييم من: المطورون الذين يدمجون بوابة القرار في CI/CD، الوكلاء، أو سير العمل المتعلقة بالامتثال المتطلبات المسبقة: الإلمام بـ JSON-RPC 2.0 و curl

النموذج العقلي: دورة حياة السيناريو

تقييم بوابات باستخدام الشروط (فحوصات الأدلة). دورة الحياة هي:

1. scenario_define  -> registers a ScenarioSpec
2. scenario_start   -> creates a RunState (new run)
3. scenario_next    -> evaluates current stage and returns a DecisionRecord

مخرجات API الرئيسية:

  • scenario_define تعيد { scenario_id, spec_hash }.
  • scenario_start يعيد الحالة الكاملة لـ RunState.
  • scenario_next returns { decision, packets, status } (a NextResult).

ما هو السيناريو؟

سيناريو هو تعريف سير العمل يتكون من:

  • Stages: Ordered steps in the workflow. Think of stages as the top-level المراحل: خطوات مرتبة في سير العمل. اعتبر المراحل كالتسلسل الأعلى الذي تنتقل من خلاله مع تقدم التشغيل.
  • Gates: Decision points inside a stage. A stage can include one or more البوابات: نقاط القرار داخل مرحلة. يمكن أن تتضمن المرحلة بوابة واحدة أو أكثر يجب اجتيازها للمضي قدمًا.
  • Conditions: Evidence checks used by gates. Each gate evaluates one or more الشروط: فحوصات الأدلة المستخدمة من قبل البوابات. تقوم كل بوابة بتقييم شرط أو أكثر لتحديد ما إذا كانت ستمر.
  • Providers: Evidence sources (builtin or MCP). Conditions don’t fetch data المزودون: مصادر الأدلة (مضمنة أو MCP). الشروط لا تستخرج البيانات بنفسها؛ بل تطلب من المزودين تقديم الأدلة للتقييم.

يمكن أن تكون المزودات:

  • مضمن: time, env, json, http
  • MCP الخارجي: أي أداة تنفذ بروتوكول evidence_query

بدء سريع

الخطوة 0: الحصول على واجهة سطر الأوامر

إذا قمت بتثبيت واجهة سطر الأوامر (CLI)، استخدم decision-gate. إذا كنت تعمل من المصدر، استخدم cargo run:

# Installed binary
decision-gate --help

# From source (repo checkout)
cargo run -p decision-gate-cli -- --help

اختبار الدخان بأمر واحد: scripts/bootstrap/quickstart.sh (bash/WSL) أو scripts/bootstrap/quickstart.ps1 (PowerShell) يقوم بتشغيل التدفق الكامل من تعريف → بدء → التالي → تشغيل الحزمة → التحقق المسبق مع معرفات فريدة.

الخطوة 1: اختر إعدادًا مسبقًا

اختر تكوينًا مسبقًا من configs/presets/ (التفاصيل في preset_configs.md). لاستخدام هذا الدليل، استخدم Quickstart-Dev لجعل التشغيل الأول سلسًا.

إعدادات مسبقة أخرى:

  • موصى به بشكل افتراضي: محلي فقط + تعيين رئيسي صريح.
  • محصن: يتطلب مصادقة الحامل + توقيع المخطط.
  • Container-Prod: مصادقة حامل + إنهاء TLS العلوي (أساسيات الحاوية).

إذا كنت ترغب في تعديل الإعدادات، قم بنسخ الإعدادات المسبقة أولاً:

cp configs/presets/quickstart-dev.toml decision-gate.toml

ملاحظات:

  • معرف مساحة الاسم الافتراضية 1 محجوز ما لم يكن namespace.allow_default = true و معرف المستأجر مدرج في namespace.default_tenants.
  • بالنسبة لربط HTTP/SSE غير المتكرر، يتطلب Decision Gate --allow-non-loopback بالإضافة إلى TLS أو server.tls_termination = "upstream" ومصادقة غير محلية. راجع security_guide.md.
  • نصيحة ويندوز: PowerShell/CMD لا تدعم curl متعددة الأسطر على نمط bash. استخدم أمرًا في سطر واحد أو سلسلة نصية PowerShell @'... '@.

الخطوة 2: بدء خادم MCP

# Installed binary:
decision-gate serve --config configs/presets/quickstart-dev.toml

# From source (repo checkout):
# cargo run -p decision-gate-cli -- serve --config configs/presets/quickstart-dev.toml

الخطوة 3: تحديد سيناريو

هذا السيناريو يعتمد على فحص الوقت: time.after(timestamp).

إذا كنت تستخدم الإعدادات المحصنة: أضف -H 'Authorization: Bearer <token>' إلى كل curl، وانتقل إلى مساحة أسماء غير افتراضية (على سبيل المثال، namespace_id: 2) لأن allow_default = false.

curl -s http://127.0.0.1:4000/rpc \
  -H 'Content-Type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "scenario_define",
      "arguments": {
        "spec": {
          "scenario_id": "quickstart",
          "namespace_id": 1,
          "spec_version": "v1",
          "stages": [
            {
              "stage_id": "main",
              "entry_packets": [],
              "gates": [
                {
                  "gate_id": "after-time",
                  "requirement": { "Condition": "after" }
                }
              ],
              "advance_to": { "kind": "terminal" },
              "timeout": null,
              "on_timeout": "fail"
            }
          ],
          "conditions": [
            {
              "condition_id": "after",
              "query": {
                "provider_id": "time",
                "check_id": "after",
                "params": { "timestamp": 1700000000000 }
              },
              "comparator": "equals",
              "expected": true,
              "policy_tags": []
            }
          ],
          "policies": [],
          "schemas": [],
          "default_tenant_id": 1
        }
      }
    }
  }'

دلالات الوقت: time.after تعيد true فقط إذا trigger_time > timestamp (أكبر بشكل صارم). تعيد المساواة false.

استجابة (مغلفة بـ MCP):

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [
      {
        "type": "json",
        "json": {
          "scenario_id": "quickstart",
          "spec_hash": { "algorithm": "sha256", "value": "<hex>" }
        }
      }
    ]
  }
}

الخطوة 4: بدء تشغيل

curl -s http://127.0.0.1:4000/rpc \
  -H 'Content-Type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/call",
    "params": {
      "name": "scenario_start",
      "arguments": {
        "scenario_id": "quickstart",
        "run_config": {
          "tenant_id": 1,
          "namespace_id": 1,
          "run_id": "run-1",
          "scenario_id": "quickstart",
          "dispatch_targets": [],
          "policy_tags": []
        },
        "started_at": { "kind": "unix_millis", "value": 1710000000000 },
        "issue_entry_packets": false
      }
    }
  }'

ملاحظة: يجب أن تكون قيم run_id فريدة. إذا قمت بإعادة تشغيل هذا الدليل، قم بتغيير run_id (على سبيل المثال، run-2) أو احذف حالة التشغيل المحلية المخزنة (decision-gate.db بشكل افتراضي).

الاستجابة (مغلفة بـ MCP): scenario_start يعيد الحالة الكاملة لـ RunState داخل result.content[0].json.

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      {
        "type": "json",
        "json": {
          "tenant_id": 1,
          "namespace_id": 1,
          "run_id": "run-1",
          "scenario_id": "quickstart",
          "spec_hash": { "algorithm": "sha256", "value": "<hex>" },
          "current_stage_id": "main",
          "stage_entered_at": { "kind": "unix_millis", "value": 1710000000000 },
          "status": "active",
          "dispatch_targets": [],
          "triggers": [],
          "gate_evals": [],
          "decisions": [],
          "packets": [],
          "submissions": [],
          "tool_calls": []
        }
      }
    ]
  }
}

الخطوة 5: تقييم بوابة التحفيز

curl -s http://127.0.0.1:4000/rpc \
  -H 'Content-Type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "id": 3,
    "method": "tools/call",
    "params": {
      "name": "scenario_next",
      "arguments": {
        "scenario_id": "quickstart",
        "request": {
          "run_id": "run-1",
          "tenant_id": 1,
          "namespace_id": 1,
          "trigger_id": "trigger-1",
          "agent_id": "agent-1",
          "time": { "kind": "unix_millis", "value": 1710000000000 },
          "correlation_id": null
        }
      }
    }
  }'

مع time.after و timestamp = 1700000000000، تعود نتيجة الفحص true لأن 1710000000000 > 1700000000000.

اختياري: أضف "feedback": "trace" داخل arguments للحصول على حالة البوابة/الشرط عندما يسمح بذلك سياسة ردود خادم.

استجابة (مغلفة بـ MCP):

{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [
      {
        "type": "json",
        "json": {
          "decision": {
            "decision_id": "decision-1",
            "seq": 1,
            "trigger_id": "trigger-1",
            "stage_id": "main",
            "decided_at": { "kind": "unix_millis", "value": 1710000000000 },
            "outcome": { "kind": "complete", "stage_id": "main" },
            "correlation_id": null
          },
          "packets": [],
          "status": "completed"
        }
      }
    ]
  }
}

استكشاف الأخطاء وإصلاحها

نتيجة البوابة هي hold

إذا لم يكن بالإمكان إثبات صحة البوابة true أو false، ستكون نتيجة القرار hold وستتضمن الاستجابة SafeSummary. بالنسبة للطلبات غير المحلية، يكون scenario_next افتراضيًا مخصصًا للتعليقات فقط؛ في وضع المحلي فقط، يكون الافتراضي trace. يمكنك دائمًا طلب feedback: "trace" (إذا كان مسموحًا) أو استخدام precheck للتكرار السريع.

{
  "result": {
    "content": [
      {
        "type": "json",
        "json": {
          "decision": {
            "outcome": {
              "kind": "hold",
              "summary": {
                "status": "hold",
                "unmet_gates": ["after-time"],
                "retry_hint": "await_evidence",
                "policy_tags": []
              }
            }
          }
        }
      }
    ]
  }
}

كيفية تصحيح الأخطاء بدقة:

  1. تصدير الـ runpack باستخدام runpack_export وفحص gate_evals وأخطاء الأدلة في البيان.
  2. استخدم evidence_query (إذا كانت سياسة الإفصاح تسمح بذلك) لإعادة إنتاج استدعاء المزود ورؤية EvidenceResult.

المصادقة مطلوبة

إذا قمت بتكوين [server.auth]، قم بتضمين رأس المصادقة المناسب:

curl -s http://127.0.0.1:4000/rpc \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -d '{ ... }'

الخطوات التالية