Skip to content

spanforge.sdk.gate — CI/CD Gate Pipeline

Module: spanforge.sdk.gate
Added in: 2.0.7 (Phase 8 — CI/CD Gate Pipeline)
Import: from spanforge.sdk import sf_gate or from spanforge.sdk.gate import SFGateClient

The gate module provides the SFGateClient singleton and the GateRunner YAML engine. It evaluates quality gates (schema validation, dependency security, secrets scanning, performance regression, and hallucination checks) against AI system artifacts and emits structured GateArtifact records with durable storage.


Quick example

from spanforge.sdk import sf_gate
from spanforge.sdk import GateVerdict

# Evaluate a single gate
result = sf_gate.evaluate(
    gate_id="schema-check",
    payload={"schema_version": "2.0", "source": "my-app@1.0.0"},
)
if result.verdict == GateVerdict.PASS:
    print(f"Gate passed in {result.duration_ms:.0f} ms")
else:
    raise RuntimeError(f"Gate {result.gate_id} {result.verdict.value}: {result.metrics}")

Singleton

spanforge.sdk.sf_gate is a module-level SFGateClient instance constructed from environment variables. For most use-cases, import and use the singleton:

from spanforge.sdk import sf_gate

status = sf_gate.get_status()
print(status.gate_count, status.artifact_count)

SFGateClient

class SFGateClient:
    def evaluate(
        self,
        gate_id: str,
        payload: dict,
        *,
        project_id: str | None = None,
    ) -> GateEvaluationResult: ...

    def evaluate_prri(
        self,
        prri_score: float,
        *,
        project_id: str | None = None,
        framework: str = "default",
        policy_file: str | None = None,
        dimension_breakdown: dict[str, float] | None = None,
    ) -> PRRIResult: ...

    def run_pipeline(
        self,
        gate_config_path: str,
        *,
        context: dict | None = None,
    ) -> GateRunResult: ...

    def get_artifact(self, gate_id: str) -> GateArtifact | None: ...

    def list_artifacts(self, *, project_id: str | None = None) -> list[GateArtifact]: ...

    def purge_artifacts(self, *, older_than_days: int = 90) -> int: ...

    def get_status(self) -> GateStatusInfo: ...

    def configure(self, config: dict) -> None: ...

evaluate(gate_id, payload, *, project_id) → GateEvaluationResult

Evaluate a single named gate against payload.


evaluate_async() — async variant

Added in: 2.0.14

async def evaluate_async(
    self,
    gate_id: str,
    payload: dict,
    *,
    project_id: str = "",
    pipeline_id: str = "",
) -> GateEvaluationResult

Non-blocking async variant of evaluate(). Delegates to the synchronous method via asyncio.get_event_loop().run_in_executor() so it never blocks the event loop. Ideal for async CI/CD runners and FastAPI-based pipelines.

ParameterTypeDefaultDescription
gate_idstr(required)Gate identifier.
payloaddict(required)Payload to evaluate.
project_idstr""Optional project scope.
pipeline_idstr""Optional pipeline label for the artifact.

Returns GateEvaluationResult

Example:

import asyncio
from spanforge.sdk import sf_gate

result = asyncio.run(
    sf_gate.evaluate_async("schema-check", {"schema_version": "2.0"})
)
assert result.verdict.value == "pass"

The evaluation applies the gate logic registered under gate_id (schema validation, secrets scan, dependency audit, performance regression check, or hallucination verifier). The result is written to the artifact store.

Parameters

ParameterTypeDescription
gate_idstrIdentifier for the gate to evaluate. Used as the artifact key.
payloaddictData to evaluate (event dict, schema snippet, config object, etc.).
project_idstr | NoneOptional project scope for artifact isolation.

Returns GateEvaluationResult

Raises

ExceptionWhen
SFGateEvaluationErrorEvaluation logic raised an error or gate returned FAIL with on_fail="block".
SFGateTrustFailedErrorTrust gate detected a blocking condition (HRI critical rate, PII window, or secrets window exceeded).

Example

from spanforge.sdk import sf_gate, GateVerdict

result = sf_gate.evaluate("dependency-audit", {"package": "requests==2.28.0"})
assert result.verdict in (GateVerdict.PASS, GateVerdict.WARN)
print(result.metrics)         # {"cve_count": 0, "severity_max": "NONE"}
print(result.artifact_url)    # ".sf-gate/artifacts/dependency-audit-<ulid>.json"

evaluate_prri(prri_score, *, project_id, framework, policy_file, dimension_breakdown) → PRRIResult

Evaluate a Pre-Release Readiness Index (PRRI) score against policy thresholds.

Scores at or above SPANFORGE_GATE_PRRI_RED_THRESHOLD (default 70) receive a RED verdict, which blocks release when on_fail="block". Scores between 30 and 69 receive AMBER (warn). Scores below 30 receive GREEN (pass).

Parameters

ParameterTypeDescription
prri_scorefloatAggregate PRRI score (0–100). Higher = more risk.
project_idstr | NoneOptional project scope.
frameworkstrPolicy framework identifier (default: "default").
policy_filestr | NonePath to a custom YAML policy file. When None, the built-in thresholds apply.
dimension_breakdowndict[str, float] | NonePer-dimension scores (e.g. {"hallucination": 0.72, "bias": 0.41}). Stored in the artifact for audit.

Returns PRRIResult

Raises SFGateEvaluationError — policy file not found, or prri_score outside [0, 100].

Example

result = sf_gate.evaluate_prri(
    65.0,
    project_id="my-agent",
    dimension_breakdown={"hallucination": 0.65, "bias": 0.50},
)
print(result.verdict)    # PRRIVerdict.AMBER
print(result.allow)      # True  (AMBER warns but does not block by default)

run_pipeline(gate_config_path, *, context) → GateRunResult

Parse and execute a YAML gate pipeline file.

The YAML file defines an ordered list of gates. Each gate has an id, type, optional pass_condition, on_fail policy (block, warn, or report), and optional parallel flag. Gates with on_fail: block that evaluate to FAIL raise SFGatePipelineError.

Parameters

ParameterTypeDescription
gate_config_pathstrPath to the gate YAML file.
contextdict | NoneRuntime context variables injected into gate commands (${var} substitution).

Returns GateRunResult — aggregate result with per-gate GateArtifact list.

Raises

ExceptionWhen
SFGateSchemaErrorYAML file is missing required fields or has an unrecognised gate type.
SFGatePipelineErrorOne or more blocking gates failed.

Example

from spanforge.sdk import sf_gate

run = sf_gate.run_pipeline(
    "examples/gates/sf-gate.yaml",
    context={"project_id": "my-agent", "env": "staging"},
)
print(run.passed, run.failed, run.warned)
for artifact in run.artifacts:
    print(f"  {artifact.gate_id}: {artifact.verdict.value}")

Gate YAML format

gates:
  - id: schema-validation
    name: "Schema Validation"
    type: schema_validation
    on_fail: block
    artifact: true

  - id: secrets-scan
    name: "Secrets Scan"
    type: secrets_scan
    on_fail: block
    artifact: true

  - id: perf-regression
    name: "Performance Regression"
    type: performance_regression
    pass_condition: "p99_latency_ms < 2000"
    on_fail: warn
    artifact: true

  - id: prri-check
    name: "PRRI Readiness Gate"
    type: halluccheck_prri
    framework: default
    on_fail: block
    artifact: true

  - id: trust-gate
    name: "Trust Gate"
    type: halluccheck_trust
    on_fail: block
    artifact: true

Gate types

TypeDescription
schema_validationValidates payload against the SpanForge v2.0 JSON Schema.
dependency_securityAudits package dependencies for known CVEs via the advisory database.
secrets_scanRuns the built-in 20-pattern secrets scanner over the target files.
performance_regressionCompares p50/p95/p99 latencies against a baseline stored in the artifact store.
halluccheck_prriEvaluates the Pre-Release Readiness Index against policy thresholds.
halluccheck_trustComposite trust gate: checks HRI critical rate, PII detection window, and secrets detection window.

Gate YAML fields

FieldRequiredDescription
idUnique gate identifier within the pipeline. Used as the artifact key.
nameHuman-readable display name.
typeGate executor type (see table above).
commandShell command to run for custom evaluation (output parsed for pass/fail).
pass_conditionBoolean expression evaluated against gate metrics (e.g. p99_latency_ms < 2000).
on_failblock (default), warn, or report. block raises SFGatePipelineError.
artifacttrue to write a GateArtifact JSON file to the artifact store.
frameworkPRRI policy framework identifier (used with halluccheck_prri).
timeout_secondsPer-gate execution timeout (default: 60).
skip_onCondition expression; when truthy the gate is skipped with SKIPPED verdict.
paralleltrue to run this gate in parallel with adjacent parallel-flagged gates.

get_artifact(gate_id) → GateArtifact | None

Retrieve the most recent stored artifact for a gate by gate_id.

Returns None if no artifact is found.

artifact = sf_gate.get_artifact("schema-validation")
if artifact:
    print(artifact.verdict, artifact.timestamp)

list_artifacts(*, project_id) → list[GateArtifact]

List all stored artifacts, optionally filtered to a project_id.

Returns artifacts sorted most-recent-first.

artifacts = sf_gate.list_artifacts(project_id="my-agent")
for a in artifacts:
    print(f"{a.gate_id}: {a.verdict.value} @ {a.timestamp}")

purge_artifacts(*, older_than_days) → int

Delete artifacts older than older_than_days. Returns the count of files removed from the artifact store.

removed = sf_gate.purge_artifacts(older_than_days=30)
print(f"Purged {removed} stale artifact(s)")

get_status() → GateStatusInfo

Return a live status snapshot of the gate subsystem.

status = sf_gate.get_status()
print(status.status)         # "ok"
print(status.gate_count)     # number of registered gate types
print(status.artifact_count) # total artifacts on disk
print(status.healthy)        # True

configure(config) → None

Override gate settings at runtime. Any keys not present keep their current (env-var-sourced or default) values.

sf_gate.configure({
    "artifact_dir": "/var/spanforge/gate-artifacts",
    "artifact_retention_days": 30,
    "prri_red_threshold": 60,
    "hri_critical_threshold": 0.03,
})

Types

All types are exported from spanforge.sdk:

from spanforge.sdk import (
    GateVerdict,
    PRRIVerdict,
    GateArtifact,
    GateEvaluationResult,
    PRRIResult,
    TrustGateResult,
    GateStatusInfo,
)

GateVerdict

class GateVerdict(str, Enum):
    PASS    = "PASS"
    FAIL    = "FAIL"
    WARN    = "WARN"
    SKIPPED = "SKIPPED"

PRRIVerdict

class PRRIVerdict(str, Enum):
    GREEN = "GREEN"   # score < 30 — release ready
    AMBER = "AMBER"   # 30 ≤ score < 70 — warn
    RED   = "RED"     # score ≥ 70 — block

GateArtifact

Immutable record written to the artifact store after gate evaluation.

FieldTypeDescription
gate_idstrGate identifier.
namestrHuman-readable gate name.
verdictGateVerdictEvaluation verdict.
metricsdictGate-specific metrics dictionary.
timestampstrISO-8601 UTC timestamp.
duration_msfloatWall-clock evaluation time.
artifact_pathstr | NoneAbsolute path to the JSON artifact file, or None if not persisted.

GateEvaluationResult

Returned by evaluate().

FieldTypeDescription
gate_idstrGate identifier.
verdictGateVerdictEvaluation verdict.
metricsdictGate-specific metrics dictionary.
artifact_urlstr | NonePath to the stored artifact file.
duration_msfloatWall-clock evaluation time.
timestampstrISO-8601 UTC timestamp.

PRRIResult

Returned by evaluate_prri().

FieldTypeDescription
gate_idstrAlways "prri".
prri_scorefloatInput score (0–100).
verdictPRRIVerdictGREEN / AMBER / RED.
dimension_breakdowndict | NonePer-dimension scores, if provided.
frameworkstrPolicy framework used.
policy_filestr | NoneCustom policy file path, if used.
timestampstrISO-8601 UTC timestamp.
allowboolTrue if the verdict does not block (GREEN or AMBER).

TrustGateResult

Returned internally by the halluccheck_trust executor; also accessible via get_artifact() after a trust gate run.

FieldTypeDescription
gate_idstrGate identifier.
verdictGateVerdictPASS, FAIL, or WARN.
hri_critical_ratefloatObserved HRI critical rate (0–1).
hri_critical_thresholdfloatConfigured threshold (from SPANFORGE_GATE_HRI_CRITICAL_THRESHOLD).
pii_detectedboolWhether PII detections exceeded the window threshold.
pii_detections_24hintPII detection count in the audit window.
secrets_detectedboolWhether secrets detections exceeded the window threshold.
secrets_detections_24hintSecrets detection count in the audit window.
failureslist[str]Human-readable description of each blocking failure.
timestampstrISO-8601 UTC timestamp.
pipeline_idstr | NonePipeline run ID, if executed via run_pipeline().
project_idstr | NoneProject scope.

GateStatusInfo

Returned by get_status().

FieldTypeDescription
statusstr"ok" or "degraded".
gate_countintNumber of registered gate executors.
artifact_countintTotal artifact files currently in the store.
artifact_dirstrAbsolute path to the artifact directory.
retention_daysintConfigured artifact retention in days.
open_circuit_breakersintCurrently open circuit breakers (always 0 for gate — informational).
healthyboolTrue when the gate subsystem is operational.

Exceptions

All exceptions are exported from spanforge.sdk:

from spanforge.sdk import (
    SFGateError,
    SFGateEvaluationError,
    SFGatePipelineError,
    SFGateTrustFailedError,
    SFGateSchemaError,
)
ExceptionBaseWhen raised
SFGateErrorSpanForgeErrorBase for all gate exceptions. Never raised directly.
SFGateEvaluationErrorSFGateErrorA single gate evaluation failed (logic error, unsupported payload, or FAIL with block policy).
SFGatePipelineErrorSFGateErrorPipeline runner encountered one or more blocking gate failures. failed_gates: list[str] attribute lists the gate IDs.
SFGateTrustFailedErrorSFGateErrorTrust gate detected a blocking condition — HRI critical rate, PII detections, or secrets detections exceeded their window threshold. trust_result: TrustGateResult attribute carries full details.
SFGateSchemaErrorSFGateErrorYAML gate configuration is invalid (missing required field, unrecognised gate type, or malformed pass condition).

Environment variables

VariableTypeDefaultDescription
SPANFORGE_GATE_ARTIFACT_DIRstring.sf-gate/artifactsDirectory where GateArtifact JSON files are persisted. Relative to the working directory; absolute paths accepted.
SPANFORGE_GATE_ARTIFACT_RETENTION_DAYSint90Artifacts older than this value are eligible for purge_artifacts().
SPANFORGE_GATE_PRRI_RED_THRESHOLDfloat70PRRI scores at or above this value receive a RED verdict and block release.
SPANFORGE_GATE_HRI_CRITICAL_THRESHOLDfloat0.05HRI critical-event rate threshold (0–1) for the trust gate. Exceeding this causes FAIL.
SPANFORGE_GATE_PII_WINDOW_HOURSint24Audit window in hours for the PII detection count check in the trust gate.
SPANFORGE_GATE_SECRETS_WINDOW_HOURSint24Audit window in hours for the secrets detection count check in the trust gate.

Test coverage

The gate module has dedicated subprocess-level mock tests for every built-in executor (tests/test_coverage_gaps.py :: TestGateExecutorSubprocessMocks).

ExecutorTestsPaths covered
_exec_schema_validation4command PASS, command FAIL (with/without stderr), generic exception
_exec_dependency_security6PASS (no vulns), FAIL (critical CVEs parsed), JSON parse error, timeout, generic exception, custom command
_exec_secrets_scan4secrets detected FAIL, fallback to unstaged diff, ImportError, generic exception
_exec_performance_regression3command PASS, command FAIL, generic exception
_exec_halluccheck_prri4command + artifact combo, timeout, malformed JSON, generic exception
_exec_halluccheck_trust6SDK PASS, SDK FAIL, artifact PASS, artifact FAIL, malformed artifact, no-SDK-no-artifact WARN

Additional gate tests in tests/test_sf_gate.py:

  • TestInferVerdictBranches (18 tests) — exercises every _infer_verdict path.
  • TestPostEvaluateHooksSideEffects (7 tests) — hook execution, failure isolation, ordering, and metrics access.
  • TestGateExecutorHelpers_evaluate_pass_condition and _substitute_template edge cases.

See also

  • Gate Pipeline user guide — Getting started, YAML examples, CI/CD integration
  • alertSFAlertClient (Phase 7) triggered by SFGateTrustFailedError
  • secrets — Secrets scanner underlying the secrets_scan gate type
  • pii — PII scanner underlying the trust gate PII window check