Skip to main content

Crate gate_contract

Crate gate_contract 

Source
Expand description

Fail-closed gate contracts for staged build pipelines.

A pipeline that only knows PASS and FAIL has a third state hiding inside it: the gate that could not be evaluated at all, because a credential was missing, an API timed out, or the value it needed was never produced. Treating that as a pass is how a run reaches deploy having checked nothing. This crate makes the third state explicit and closes it.

The rule enforced throughout:

A blocking gate halts the run when it fails and when it cannot be evaluated. “Could not check” is not “fine”.

§The pieces

  • OutcomePass, Fail, or Unevaluable, each carrying a reason string.
  • Known — a value that may be Unknown; unknown propagates through combination instead of decaying into a default.
  • Gate — an id, a Severity (blocking or advisory) and an outcome.
  • Stage — a named set of gates, evaluated together so one run reports every failure.
  • Pipeline — ordered stages, halting at the first stage that halts.

§Example

use gate_contract::{Gate, Severity, Stage, Verdict};

let stage = Stage::new("harvest")
    .with_gate(Gate::pass("serp-rows-present"))
    .with_gate(Gate::unevaluable("rdap-reachable", "no credential on disk"));

let report = stage.evaluate();
assert!(report.halted());
match report.verdict {
    Verdict::Halt { ref gate_id, .. } => assert_eq!(gate_id, "rdap-reachable"),
    Verdict::Proceed => unreachable!(),
}

An advisory gate records the same information without stopping anything:

use gate_contract::{Gate, Stage};

let report = Stage::new("design")
    .with_gate(Gate::fail("tone-check", "two sentences flagged").advisory())
    .evaluate();
assert!(!report.halted());
assert_eq!(report.warnings().len(), 1);

No dependencies, no I/O, no unsafe. Evaluating what a gate means is this crate’s job; deciding what to measure is yours.

Extracted from a real staged build pipeline, whose first blocking gate is worked through in public at https://aiwebsitepipeline.com/niche-score.html: six subscores, the weights that combine them, and the thresholds that decide the run — 55 and above proceeds, 40 to 55 proceeds under a page cap, below 40 the run halts. That page is a concrete example of the shape Severity::Blocking exists to express, and is worth reading before deciding what your own gates should refuse.

Structs§

Gate
One contract: an identifier, a severity and an outcome.
GateCounts
Tallies from one stage evaluation.
Pipeline
Ordered stages evaluated until one halts.
RunReport
The outcome of a whole pipeline run.
Stage
A named set of gates evaluated together.
StageReport
The outcome of evaluating a Stage.

Enums§

HaltCause
Why a run halted.
Known
A value that may not exist yet.
Outcome
The result of evaluating one gate.
Severity
Whether a gate can stop the run.
Verdict
What the caller should do next.