Decision Gate Docs

Avaluació de portes determinista, reproduïble amb decisions auditable.

Asset Core docs

Començant amb Decision Gate

A Simple Vista

Què: Executar un escenari mínim de Decision Gate localment Per què: Veure el cicle de vida complet: definir -> iniciar -> avaluar Qui: Desenvolupadors que integren Decision Gate en fluxos de treball de CI/CD, agents o de compliment Requisits previs: Familiaritat amb JSON-RPC 2.0 i curl

Model Mental: Cicle de Vida de l’Escenari

La Decision Gate avalua gates utilitzant condicions (comprovacions d’evidència). El cicle de vida és:

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

Produccions clau de l’API:

  • scenario_define retorna { scenario_id, spec_hash }.
  • scenario_start retorna l’estat complet RunState.
  • scenario_next retorna { decision, packets, status } (un NextResult).

Què és un Escenari?

Un escenari és una definició de flux de treball composta per:

  • Stages: Ordered steps in the workflow. Think of stages as the top-level Etapes: Passos ordenats en el flux de treball. Penseu en les etapes com la seqüència de nivell superior per la qual es passa a mesura que avança una execució.
  • Gates: Decision points inside a stage. A stage can include one or more Gates: Punts de decisió dins d’una etapa. Una etapa pot incloure un o més gates que s’han de superar per avançar.
  • Conditions: Evidence checks used by gates. Each gate evaluates one or more Condicions: Comprovacions d’evidència utilitzades pels gates. Cada gate avalua una o més condicions per decidir si es supera.
  • Providers: Evidence sources (builtin or MCP). Conditions don’t fetch data Proveïdors: Fonts d’evidència (integrades o MCP). Les condicions no recuperen dades per si mateixes; demanen als proveïdors evidència per avaluar.

Els proveïdors poden ser:

  • Integrat: time, env, json, http
  • MCP extern: qualsevol eina que implementi el protocol evidence_query

Inici ràpid

Pas 0: Obteniu el CLI

Si has instal·lat la CLI, utilitza decision-gate. Si estàs executant des del codi font, utilitza cargo run:

# Installed binary
decision-gate --help

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

Prova de fum d’un sol comandament: scripts/bootstrap/quickstart.sh (bash/WSL) o scripts/bootstrap/quickstart.ps1 (PowerShell) executa el flux complet de definir → iniciar → següent → executar paquet → precomprovació amb IDs únics.

Pas 1: Trieu un preset

Trieu una configuració predefinida de configs/presets/ (detalls a preset_configs.md). Per a aquesta guia, utilitzeu Quickstart-Dev per mantenir la primera execució sense friccions.

Altres preconfiguracions:

  • Per defecte-recomanat: només local + mapeig principal explícit.
  • Endurit: s’exigeix autenticació de portador + signatura de esquema.
  • Container-Prod: autenticació bearer + terminació TLS ascendent (baseline del contenidor).

Si voleu editar la configuració, primer copieu el preset:

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

Notes:

  • La id de l’espai de noms per defecte 1 està bloquejada a menys que namespace.allow_default = true i la id del llogater estigui llistada en namespace.default_tenants.
  • Per a les connexions HTTP/SSE que no són de loopback, Decision Gate requereix --allow-non-loopback més TLS o server.tls_termination = "upstream" i autenticació no local. Vegeu security_guide.md.
  • Consell de Windows: PowerShell/CMD no suporten curl en múltiples línies al estil bash. Utilitzeu un comandament d’una sola línia o la cadena aquí @'... '@ de PowerShell.

Pas 2: Iniciar el servidor 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

Pas 3: Defineix un Escenari

Aquest escenari depèn d’una comprovació de temps: time.after(timestamp).

Si utilitzeu la preset Hardened: afegiu -H 'Authorization: Bearer <token>' a cada curl, i canvieu a un espai de noms no predeterminat (per exemple, namespace_id: 2) perquè 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
        }
      }
    }
  }'

Semàntica del temps: time.after retorna true només si trigger_time > timestamp (estrictament més gran). La igualtat retorna false.

Resposta (embolcallada en MCP):

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

Pas 4: Iniciar una Execució

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
      }
    }
  }'

Nota: els valors de run_id han de ser únics. Si torneu a executar aquesta guia, canvieu run_id (per exemple, run-2) o suprimiu l’estat local de la execució (decision-gate.db per defecte).

Resposta (MCP-embolcallada): scenario_start retorna el RunState complet dins de 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": []
        }
      }
    ]
  }
}

Pas 5: Avaluació de la Porta de Trigger

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
        }
      }
    }
  }'

Amb time.after i timestamp = 1700000000000, la comprovació retorna true perquè 1710000000000 > 1700000000000.

Opcional: afegiu "feedback": "trace" dins arguments per obtenir l’estat de la porta/condició quan ho permeti la política de retroalimentació del servidor.

Resposta (embolcallada en 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"
        }
      }
    ]
  }
}

Solució de problemes

El resultat de la porta és hold

Si una porta no es pot demostrar true o false, el resultat de la decisió serà hold i la resposta inclourà un SafeSummary. Per a sol·licituds no locals, scenario_next per defecte és un feedback només de resum; en mode només local, el valor per defecte és trace. Sempre podeu sol·licitar feedback: "trace" (si està permès) o utilitzar precheck per a una iteració ràpida.

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

Com depurar amb precisió:

  1. Exporta el runpack amb runpack_export i inspecciona gate_evals i els errors d’evidència al manifest.
  2. Utilitzeu evidence_query (si la política de divulgació ho permet) per reproduir la crida del proveïdor i veure el seu EvidenceResult.

Auth Required

Si configureu [server.auth], incloeu l’encapçalament d’autenticació apropiat:

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

Properes passes