Decision Gate Docs

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

Asset Core docs

Requirement Evaluation Trees (RET)

A Simple Vista

Què: Àlgebra booleana per a portes, amb gestió d’incògnites (lògica de tres estats) Per què: Fer que la lògica de les portes sigui explícita, auditable i determinista - sense regles ocultes Qui: Desenvolupadors i operadors que redacten requisits complexos de portes Requisits previs: Comprensió bàsica de les condicions (vegeu condition_authoring.md)

Backend Baixat/AOT (RET)

RET ara proporciona un backend additiu rebaixat/AOT a ret-logic:

  • Compila una vegada: Requirement<P> -> CompiledRequirement<K>
  • Evaluate fast paths at runtime:
    • CompiledRequirement::eval
    • CompiledRequirement::eval_block
    • CompiledRequirement::eval_tristate (+ variant de traç)
  • Export deterministic predicate-key dependencies:
    • CompiledRequirement::predicate_keys()
  • Compute explanation-oriented residual/progress views:
    • Requirement::residual
    • CompiledRequirement::residual
  • Preserve compatibility:
    • Tree-walk Requirement::eval* es manté suportat i sense canvis.

Això és independent del domini: els dominis subministren un mapeig de claus determinista (PredicateRegistry) i una execució de claus en temps d’execució (PredicateRuntime). L’explicació residual/progrés requereix addicionalment implementacions de progrés a nivell de condició o predicat a través de ConditionProgressEval i PredicateProgressRuntime.

Ingesta en temps de compilació vs en temps d’execució

La ingesta de fonts (RON, JSON, DSL, càrregues MCP, etc.) no canvia la semàntica de RET. La diferència és el cicle de vida:

  • Compile-time/load-time ingestion: parse + validate + compile once, store artifact compilat.
  • Runtime ingestion: parse + validate + compile when the gate arrives, then executar artefacte compilat.

Ambdós camins convergeixen en el mateix comportament d’àlgebra i avaluador compilat quan els requisits d’entrada són equivalents.


Per què RET?

Problema: Com es poden combinar múltiples verificacions d’evidència en una única decisió de porta?

Escenari d’exemple: “Vull desplegar a producció si:

  • L’entorn és ‘producció’ I
  • Les proves han passat I
  • La cobertura és superior al 85% I
  • Almenys 2 de 3 revisors han aprovat

Sense RET: Hauries d’escriure codi personalitzat per a cada Decision Gate, que és:

  • No auditable (la lògica està oculta en el codi)
  • No determinista (el codi pot canviar entre execucions)
  • Difícil de verificar fora de línia (no es pot reproduir sense tornar a executar el codi)

Amb RET: Expreseu la lògica com una estructura d’arbre:

{
  "requirement": {
    "And": [
      { "Condition": "env_is_prod" },
      { "Condition": "tests_ok" },
      { "Condition": "coverage_ok" },
      {
        "RequireGroup": {
          "min": 2,
          "reqs": [
            { "Condition": "alice_approved" },
            { "Condition": "bob_approved" },
            { "Condition": "carol_approved" }
          ]
        }
      }
    ]
  }
}

Beneficis:

  • Explícit: La lògica és visible en l’especificació de l’escenari
  • Auditable: Cada avaluació es rastreja en el runpack
  • Determinista: Mateixa evidència -> mateix resultat
  • Repetible: Pot verificar-se offline sense tornar a consultar els proveïdors

[Seguretat]: La lògica de porta explícita impedeix portes posteriors ocultes. Tota la lògica es declara en l’especificació de l’escenari i es rastreja en el paquet d’execució per a auditoria.


Model Mental: Arbre d’Avaluació RET

Aquí teniu com es valora un arbre de requisits:

RET EVALUATION TREE (simplified)

Gate Requirement (tree structure)
  And
  |-- Pred(A) -> true
  |-- Pred(B) -> unknown
  |-- Not(C) -> false
  `-- RequireGroup (min: 2)
      |-- Pred(D) -> true
      |-- Pred(E) -> true
      `-- Pred(F) -> false

Strong Kleene Logic: And(true, unknown, true, true) -> unknown
(gate holds)

Ordre d’avaluació:

  1. Les condicions de fulla s’avaluen en un estat de tres valors (veritable/fals/desconegut)
  2. Els nodes operadors combinen resultats fills mitjançant lògica de tres estats
  3. L’outcome del node arrel determina el resultat de la porta

Tri-State Outcomes

RET utilitza lògica de tres estats (no només veritable/fals):

  • true: Passis d’accés (tots els requisits satisfets)
  • false: La porta falla (requisits contradits)
  • unknown: Retencions de porta (requisits inconclusos)

Per què tri-estat? Les portes fallan tancades: una porta només es permet passar quan el requisit s’avalua com a true. Els resultats unknown impedeixen que les portes passin fins que l’evidència estigui completa.

Exemple:

Gate: And(tests_ok, coverage_ok)
Conditions:
- tests_ok: true (tests passed)
- coverage_ok: unknown (coverage report missing)

Outcome: unknown (gate holds until coverage is available)

Operadors Bàsics

I

Semàntica: Tots els nens han de ser true

Truth table (2 operands):

LeftRightResult
truetruetrue
truefalsefalse
trueunknownunknown
false(any)false
unknowntrueunknown
desconegutdesconegutdesconegut

Exemple:

{
  "requirement": {
    "And": [
      { "Condition": "tests_ok" },
      { "Condition": "coverage_ok" }
    ]
  }
}

Cas d’ús: Tant les proves com la cobertura han de passar

Comportament:

  • Tot true -> true (passis de porta)
  • Any false -> false (la porta falla)
  • Altrament -> unknown (la porta es manté)

O bé

Semàntica: Qualsevol fill pot ser true

Truth table (2 operands):

LeftRightResult
true(any)true
falsefalsefalse
falseunknownunknown
unknownfalseunknown
desconegutdesconegutdesconegut

Exemple:

{
  "requirement": {
    "Or": [
      { "Condition": "manual_override" },
      { "Condition": "tests_ok" }
    ]
  }
}

Cas d’ús: O bé sobreescriptura manual O bé proves automatitzades han de passar

Comportament:

  • Any true -> true (passos de porta)
  • Tot false -> false (la porta falla)
  • Altrament -> unknown (la porta es manté)

No

Semàntica: Invertir l’outcome del fill

Truth table:

InputResult
truefalse
falsetrue
Taula de veritat:Entrada

Exemple:

{
  "requirement": {
    "And": [
      { "Condition": "tests_ok" },
      { "Not": { "Condition": "blocklist_hit" } }
    ]
  }
}

Cas d’ús: Les proves han de passar I la llista negra NO ha de ser activada

Comportament:

  • true -> false
  • fals -> cert
  • unknown -> desconegut (fail-closed: no es pot confirmar l’absència)

RequireGroup (Quorum)

Semàntica: Almenys N de M nens han de ser true

Paràmetres:

  • min: Nombre mínim de resultats true requerits
  • reqs: Array de requisits fills

Exemple:

{
  "requirement": {
    "RequireGroup": {
      "min": 2,
      "reqs": [
        { "Condition": "alice_approved" },
        { "Condition": "bob_approved" },
        { "Condition": "carol_approved" }
      ]
    }
  }
}

Cas d’ús: Almenys 2 de 3 revisors han d’aprovar

Comportament:

  • Comptar resultats true
  • Si el compte >= min -> true (quorum assolit)
  • Si count + unknowns < min -> false (quòrum impossible)
  • Altrament -> unknown (quorum pendent)

Truth table examples:

OutcomesminResultReason
[true, true, false]2true2 true >= min (quorum reached)
[true, unknown, unknown]2unknown1 true, can’t reach min yet
[true, false, false]2false1 true, max possible is 1 < min
[true, true, unknown]2true2 true >= min (already met)
[fals, fals, fals]2fals0 vertader, impossible

[Desenvolupador]: Vegeu ret-logic crate per a la implementació. RequireGroup compta veritable/fals de manera independent (desconegut no és ni veritable ni fals).


Condició (Fulla)

Semàntica: Referència a una condició per clau

Exemple:

{
  "requirement": { "Condition": "tests_ok" }
}

Cas d’ús: Porteria simple amb una única condició

Comportament:

  • Avalua el resultat tri-estat de la condició
  • La condició ha d’existir a ScenarioSpec.conditions

Regles de Propagació Tri-Estat

Com es propaguen els resultats unknown a través dels operadors:

I Propagació

OperandsResultReason
And(true, true, true)trueTots els requisits satisfets
And(true, false, true)falseUn falla -> And falla
And(true, unknown, true)unknownNo es pot confirmar que tots siguin true encara
And(false, unknown)falseUn falla (curtcircuit)
And(unknown, unknown)unknownEvidència pendent

Regla: false domina; tot true dóna true; altrament unknown


O Propagació

OperandsResultatRaó
Or(false, false, false)falseTots els requisits han fallat
Or(true, false, false)trueUn té èxit -> Or té èxit
Or(false, unknown, false)unknownNo es pot confirmar que tots siguin falsos encara
Or(true, unknown)trueUn té èxit (curtcircuit)
Or(unknown, unknown)unknownEvidència pendent

Regla: true domina; tot false dóna false; altrament unknown


RequireGroup Propagation

Resultatsmincomptatge veritablecomptatge desconegutResultat
[T, T, F]220veritable (min assolit)
[T, U, U]212desconegut (max 3, necessiten 2)
[T, F, F]210fals (max 1 < min)
[U, U, U]203desconegut (max 3, necessiten 2)
[F, F, F]200fals (impossible)

Regla:

  • Si true_count >= min -> true (quòrum assolit)
  • Si true_count + unknown_count < min -> false (quòrum impossible)
  • Altrament -> unknown (quorum pendent)

[LLM Agent]: Quan RequireGroup retorna unknown, necessites més proves. Comprova quines condicions són desconegudes i treballa per satisfer-les.


Casos d’ús pràctics

Simple Gate: Ambdues Condicions

Escenari: Desplegar si les proves han passat I la cobertura és superior al 85%

{
  "gate_id": "quality_gate",
  "requirement": {
    "And": [
      { "Condition": "tests_ok" },
      { "Condition": "coverage_ok" }
    ]
  }
}

Quorum Gate: 2 de 3 Revisors

Escenari: Fusionar PR si almenys 2 de 3 revisors han aprovat

{
  "gate_id": "review_gate",
  "requirement": {
    "RequireGroup": {
      "min": 2,
      "reqs": [
        { "Condition": "alice_approved" },
        { "Condition": "bob_approved" },
        { "Condition": "carol_approved" }
      ]
    }
  }
}

Exclusió Porta: NO a la llista negra

Escenari: Desplegar si NO està a la llista negra

{
  "gate_id": "blocklist_gate",
  "requirement": {
    "Not": { "Condition": "blocklist_hit" }
  }
}

Complex Gate: (A I B) O C

Escenari: Desplegar si (les proves han passat I la cobertura és correcta) O sobreescriptura manual

{
  "gate_id": "deploy_gate",
  "requirement": {
    "Or": [
      {
        "And": [
          { "Condition": "tests_ok" },
          { "Condition": "coverage_ok" }
        ]
      },
      { "Condition": "manual_override" }
    ]
  }
}

Ramificació en Resultats de Portes

Podeu dirigir-vos a diferents etapes en funció dels resultats de les portes utilitzant advance_to.branch:

{
  "advance_to": {
    "kind": "branch",
    "branches": [
      { "gate_id": "env_gate", "outcome": "true", "next_stage_id": "ship" },
      { "gate_id": "env_gate", "outcome": "unknown", "next_stage_id": "hold" },
      { "gate_id": "env_gate", "outcome": "false", "next_stage_id": "deny" }
    ],
    "default": null
  }
}

Com funciona:

  1. Avaluar el gate env_gate
  2. Comprovar el resultat contra les branques (de dalt a baix)
  3. La primera branca coincident guanya
  4. Si no hi ha coincidència i default és nul -> error

Casos d’ús:

  • Cert: Avançar al desplegament en producció
  • Desconegut: Esperar revisió manual
  • Fals: Rebutjar i notificar

[Seguretat]: Utilitzeu ramificacions per implementar alternatives de seguretat. Per exemple, rutegeu unknown a revisió manual en comptes d’avançar automàticament.


Logic Mode: Strong Kleene

Decision Gate utilitza lògica Kleene forta (tres estats):

Propertats clau:

  • And(true, unknown) -> unknown (no es pot confirmar que tot sigui cert)
  • Or(false, unknown) -> unknown (no es pot confirmar que tot sigui fals)
  • Not(unknown) -> unknown (no es pot invertir la incertesa)

Alternativa (no utilitzada): Lògica de Bochvar (qualsevol desconegut -> desconegut)

Per què Kleene?

  • Més intuïtiu per a proves parcials
  • Curt-circuits quan sigui possible (And(false, unknown) -> false)
  • Els equilibris fallen tancats amb usabilitat

[Desenvolupador]: Vegeu crates/ret-logic/src/lib.rs per a l’algorisme d’avaluació.


Casos d’ús

Primari: Portes complexes que requereixen combinacions booleanes (I, O, quòrum) Secundari: Portes simples amb condicions úniques (només node de condició) Antipatró: No anideu RETs massa profundament - preferiu condicions enfocades i arbres plans


Solució de problemes

Problema: Porta enganxada en unknown

Síntomes: La porta mai passa, sempre retorna unknown

Causa: Una o més condicions s’estan avaluant com a unknown

Solució:

  1. Comproveu el rastre de la porta per veure quines condicions són unknown
  2. Solucioneu els problemes de condicions subjacents (vegeu condition_authoring.md)
  3. Common causes:
    • Error del proveïdor (per exemple, fitxer absent per al proveïdor json)
    • JSONPath no trobat (desajustament de l’eina)
    • Incompatibilitat de tipus per a un comparador sensible al tipus

Problema: RequireGroup Mai Passa

Síntomes: RequireGroup sempre retorna false o unknown

Causa: min és massa alt, o massa condicions estan fallant

Solució:

  1. Comprovar el valor min en comparació amb el nombre de condicions
  2. Verifiqueu els resultats de condició en el rastre de la porta
  3. Assegureu-vos que almenys min condicions poden ser true simultàniament

Exemple:

// BAD: min is 3, but only 2 conditions
{
  "RequireGroup": {
    "min": 3,
    "reqs": [
      { "Condition": "a" },
      { "Condition": "b" }
    ]
  }
}

// GOOD: min <= number of conditions
{
  "RequireGroup": {
    "min": 2,
    "reqs": [
      { "Condition": "a" },
      { "Condition": "b" },
      { "Condition": "c" }
    ]
  }
}

Problema: La branca no coincideix

Síntomes: Error d’evaluació de la porta: “No hi ha cap branca coincident”

Causa: El resultat de la porta no coincideix amb cap branca, i default és nul

Solució:

  1. Afegiu branques per a tots els possibles resultats (veritable/fals/desconegut)
  2. OR estableix default a una etapa de reserva
  3. Exemple:
{
  "branches": [
    { "gate_id": "gate1", "outcome": "true", "next_stage_id": "ship" },
    { "gate_id": "gate1", "outcome": "false", "next_stage_id": "deny" }
  ],
  "default": "hold"  // Fallback for unknown
}

Consells d’autoria

1. Mantingueu les claus de condició estables i descriptives

  • Utilitzeu tests_ok no pred1
  • Les claus es referencien en runpacks per a auditoria

2. Utilitzeu RequireGroup per a comprovacions de tipus quorum

  • Exemple: “2 de 3 revisors”, “3 de 5 comprovacions de datacenter”
  • Alternativa: Múltiples condicions And (però menys flexibles)

3. Preferir arbres més petits amb condicions enfocades

  • Més fàcil d’auditar i entendre
  • Més fàcil de depurar quan fallen les portes

4. Validar l’estructura RET durant la definició de l’escenari

  • La Decision Gate valida els RETs en el moment de scenario_define
  • Fallida ràpida si l’estructura és invàlida (per exemple, referenciant condicions inexistents)

5. Utilitzeu ramificacions per a solucions de seguretat en cas de fallada

  • Rutar unknown a revisió manual
  • Ruta false per alertar/denegar
  • Route true per avançar

Camins d’Aprenentatge de Referència Creuada

Camí de Nou Usuari: getting_started.md -> condition_authoring.md -> AQUESTA GUIA -> integration_patterns.md

Camí de Lògica Avançada: AQUESTA GUIA -> evidence_flow_and_execution_model.md -> Entendre com s’integren els RETs en el pipeline d’avaluació

Camí de Seguretat: AQUESTA GUIA -> security_guide.md -> Apreneu com la lògica explícita evita portes enrere


Glossari

I: Operador que requereix que tots els nens siguin true.

Porta: Punt de decisió en un escenari, avaluat mitjançant RET contra proves.

O: Operador que requereix que qualsevol fill sigui true.

Nota: Operador que inverteix el resultat del fill (true <-> false).

Condició: Definició de comprovació d’evidències: consulta + comparador + valor esperat.

RequireGroup: Operador de quòrum que requereix almenys N de M fills per ser true.

RET: Arbre d’Avaluació de Requisits, àlgebra booleana (I/O/No/RequerirGrup) per a portes.

TriState: Resultat de l’avaluació: true (aprovat), false (suspendre) o unknown (en espera).

Lògica Kleene Forta: Mode de lògica de tres estats on And(true, unknown) -> unknown.