Governance Gate System

Policy-driven approval gates that enforce quality, compliance, and review requirements at lifecycle boundaries.

Synopsis

Gate status is queried via MCP resource:

apogee://status/gates

Description

The gate system evaluates a policy file (apogee.policy.json) against the current project state to determine whether lifecycle transitions are permitted.

Policy conditions map symbolic codes to severity levels. For example, missing_proof_report might be a blocker in a released project but acceptable in a pre-release project.

Lifecycle-stage awareness: the evaluator adjusts severity defaults based on the project’s lifecycle stage (pre-release vs released). Pre-release projects can relax gates that would block a released product.

Immutable gates: some gates declared in skill metadata are non-overridable — they cannot be relaxed by policy configuration.

Configuration

Policy file: apogee.policy.json at the repository root.

{
  "policy_version": "1",
  "policy_name": "default",
  "lifecycle_stage": "pre-release",
  "default_band": "ship-quality",
  "conditions": {
    "missing_proof_report": "acceptable",
    "missing_unit_tests": "warning"
  }
}

Reference

Key classes

  • GatePolicy — immutable acceptance-gate configuration (version, name, band, lifecycle stage, conditions, required reports/runners)

  • GateMetadata — per-workflow gate declaration (has_approval_gate, immutable flag)

  • GateMetadataProvider — protocol for providing gate metadata

Evaluator API

evaluate_gates(inventory, policy)GateSummary

Pure evaluation function (no I/O). Returns findings with severity ordering: blocker > warning > informational.

Severity levels: blocker, warning, acceptable, informational.

Examples

Querying gate status from a chain step or automation script:

# Check gate status for a feature
gate_status = read_resource("apogee://status/gates")

# Evaluate gates against policy
# Returns: blocker/warning/acceptable/informational per gate
for finding in gate_status["findings"]:
    if finding["severity"] == "blocker":
        raise GateBlockedError(finding["code"], finding["message"])

Programmatic evaluation without MCP (e.g. in tests):

from apogee_engine.gate_evaluator import evaluate_gates
from apogee_engine.gate_policy import GatePolicy

policy = GatePolicy.from_file("apogee.policy.json")
summary = evaluate_gates(inventory, policy)

assert summary.passed, f"Blocked by: {summary.blockers}"

What a gate looks like in practice

A developer completing a feature chain reaches a release-tier step. The chain engine evaluates gates before allowing the transition:

==> Gate evaluation: release-readiness
======================================
  missing_unit_tests         warning
  missing_proof_report       BLOCKER
  manifest_stale             acceptable
--------------------------------------
  Verdict: BLOCKED — resolve blockers before proceeding.
======================================

Blocker detail:
  missing_proof_report: No proof report found for feature
  "incremental-branch-loading". Run the proof harness to
  generate one:
     apogee-proof-harness --suite incremental-branch-loading

The developer runs the proof harness, the report is written to apogee_artifacts/, and the gate re-evaluates on the next execute_chain(action="next"). Once all blockers clear, the chain proceeds.

In CI: the same evaluation runs headless. A blocker sets a non-zero exit code. The apogee.policy.json file controls which conditions are blockers vs warnings — a pre-release project can mark missing_proof_report as acceptable while a released project treats it as a blocker.

Severity Levels

Level

Meaning

Action

blocker

Prevents lifecycle progression

Must resolve before the transition is permitted

warning

Should be addressed

Review and resolve before release

acceptable

Known and accepted risk

Document the acceptance reason in policy

informational

For-your-information only

No action needed; logged for audit trail

Severity ordering is strict: blocker > warning > acceptable > informational. The evaluator short-circuits on the first blocker unless the caller requests a full scan.

Immutable Gates

Some gates declared in skill metadata carry the immutable flag. These gates cannot be overridden by policy exceptions or lifecycle stage relaxations.

Immutable gates exist for conditions where relaxation would compromise the integrity of the verification process itself. Examples include:

  • Proof report presence — a proof report must exist before any release-tier transition, regardless of policy.

  • Manifest freshness — the manifest must not be stale beyond a configured threshold.

  • Chain completion — all required chain steps must have recorded outcomes before finalization.

Immutable gates are identified by the immutable: true flag in GateMetadata. The evaluator enforces them unconditionally:

{
  "gate_code": "missing_proof_report",
  "has_approval_gate": true,
  "immutable": true
}

Policy conditions that attempt to relax an immutable gate are silently ignored by the evaluator. A validation warning is emitted in the gate summary when this occurs.

Note

This page is also available as a man page: man apogee-gates

See Also

  • Chain Engine — chains that insert gates at boundaries

  • apogee-proof — proof reports consumed by gate checks

  • apogee-mcp — MCP resource endpoint for apogee://status/gates

  • Glossary — terminology definitions for gate-related concepts