Gate Engine
The gate engine is StateAnchor's breaking change detection and policy enforcement system. On every push, it diffs the incoming spec against the previous canonical IR, scores each change by breaking severity, and produces a gate decision: allow, warn, or block.
How it works
The gate engine runs synchronously in the GitHub Action flow. After the spec validates, StateAnchor calls the gate-check endpoint which: (1) loads the previous IR from the most recent completed sync run, (2) converts the incoming stateanchor.yaml to a lightweight IR, (3) runs a structural diff, (4) applies any active drift exceptions, (5) evaluates the effective score against policy thresholds.
Desired state vs observed state
StateAnchor follows a Kubernetes-style desired-state model. Your stateanchor.yaml is the desired state. The previous IR stored in the database is the last observed state. The diff between them is the delta that gets scored. If the delta contains breaking operations above the threshold, the gate blocks.
Scoring model
Every change detected by spec-diff is assigned a score based on its breaking severity. Scores are additive — multiple breaking changes in a single push are summed.
| Operation | Score | Severity | Description |
|---|---|---|---|
endpoint_removed | 40 | error | An existing endpoint was deleted |
auth_changed | 35 | error | Authentication scheme was changed |
field_removed | 30 | error | A response or request field was removed |
oneOf_anyOf_modified | 30 | error | Union type structure was changed |
type_changed | 25 | error | Field type was changed (e.g., string → number) |
enum_value_removed | 25 | error | An enum value was removed |
required_added | 20 | warning | A new required parameter was added |
field_renamed | 15 | warning | A field was renamed |
endpoint_added | 0 | info | A new endpoint was added |
field_added_optional | 0 | info | A new optional field was added |
description_changed | 0 | info | Only the description text changed |
Thresholds
The gate engine uses three thresholds to determine the action:
| Score range | Action | Behavior |
|---|---|---|
| 0 | allow | No breaking changes. Sync proceeds. |
| 1–20 | warn | Minor changes. Sync proceeds with warning. |
| 21–60 | approval_required | Breaking changes require acknowledgment. |
| > 60 | block | Major breaking changes. Sync is rejected. |
Default thresholds: warn_threshold = 20, block_threshold = 60. These can be configured per-project.
Aggregation
The effective breaking score is calculated as: sum of all breaking item scores MINUS scores of items suppressed by active drift exceptions. Example: if a push removes an endpoint (score 40) but an active exception exists for that endpoint+kind, the effective score is 0.
GitHub Action integration
The gate result is returned to the GitHub Action as structured output:
| Output | Description |
|---|---|
gate-action | allow, approval_required, or block |
gate-score | Effective breaking score (integer) |
sync-run-id | UUID of the sync run created |
If gate-action is "block", the Action exits with a non-zero status code and the workflow fails. The block reason and breaking operations are logged to the Actions summary.
Handling a blocked push
When the gate blocks a push, you have three options:
- Fix the breaking change — modify the spec to avoid the breaking operation.
- Create a drift exception — in project settings, add an exception for the specific endpoint+operation. Exceptions have a maximum 90-day TTL.
- Adjust thresholds — raise the
block_thresholdif your team accepts higher risk.
Exception ledger
Drift exceptions suppress specific breaking operations from the score calculation. Each exception is scoped to a project, endpoint, and change kind. Exceptions expire automatically (max 90 days). When an exception expires, the item re-activates and the gate may block again on the next push.
Recommended operating model
Start with default thresholds. Let the gate warn on your first few syncs to calibrate. Once you trust the scoring, enable blocking. Create exceptions only for intentional migrations. Review exception expiry dates monthly.