← Back to blog
Feature note2026-07-20 09:00 UTC

Turning Ota Contracts into Merge-Gate Truth

How Ota turns contract-owned verification lanes into stable merge-check identities, CI drift findings, and an opt-in GitHub pull-request gate.

Overview

Most repositories already have a merge gate.

The problem is that its truth usually lives inside provider configuration:

  • a GitHub Actions workflow
  • a GitLab pipeline
  • a branch-protection check name
  • a shell command copied into several jobs
  • a convention that reviewers are expected to remember

That makes CI look authoritative while quietly creating a second operating model beside the repository itself.

The repo says one thing. The workflow says another. Both can remain internally valid while drifting apart.

Ota takes a stricter position: the repository contract should own what must be verified. The CI provider should own when and where that verification runs.

That separation lets Ota turn a declared verification workflow into machine-readable merge-gate truth without pretending it owns GitHub, GitLab, branch protection, secrets, runners, or deployment policy.

The Two-Sources-of-Truth Problem

Imagine a repository where ota.yaml declares verify as the canonical CI lane, but the GitHub workflow still runs an older command.

Both files parse. The workflow may even stay green.

But the repository now has two answers to a basic governance question:

What must pass before this change is trusted?

That drift commonly appears as:

  • a contract adds a required verification lane but CI never runs it
  • CI changes a verification command without updating the contract
  • a workflow hardcodes a different Ota version or installation source
  • a renamed job silently changes the status context used by branch protection
  • one operating-system lane keeps running while another disappears

Waiting for a cryptic CI failure is too late. The contract-to-provider relationship should be inspectable before merge.

The Contract Owns The Verification Lane

The starting point is a reviewed Ota workflow with explicit CI intent:

OTA.YAMLyaml
version: 1project:  name: api tasks:  verify:    description: Run the canonical verification lane    safe_for_agent: true    command:      exe: npm      args: [test] workflows:  default: verify  verify:    intent: ci_verification    run:      task: verify agent:  safe_tasks: [verify]  bootstrap:    ota:      source:        kind: version        version: v1.6.24

This contract establishes several pieces of governance truth:

  • verify is a declared task, not an arbitrary workflow shell string
  • the workflow has merge-relevant ci_verification intent
  • the selected lane is available to the enforced agent execution boundary
  • CI bootstrap can consume the same contract-owned Ota source

The contract does not declare pull_request, ubuntu-latest, repository secrets, deployment environments, or notification behavior. Those remain provider-owned concerns.

Ota Projects Stable Merge Identity

Run:

INSPECT MERGE GOVERNANCEbash
ota doctor --json

When the contract declares merge-relevant verification truth, Doctor can publish:

  • governance.required_verification_lanes[]
  • governance.merge_gate

An abridged record looks like this:

MERGE-GATE PROJECTIONjson
{
  "governance": {
    "required_verification_lanes": [
      {
        "merge_check_id": "ota.verify.verify",
        "lane_task": "verify",
        "lane_kind": "task",
        "contract_sources": ["workflows.verify.run.task"]
      }
    ],
    "merge_gate": {
      "state": "projected",
      "blocking": false,
      "required_lane_count": 1,
      "drift_lane_count": 0,
      "decision_basis": [
        {
          "id": "projection:ota.verify.verify",
          "family": "required_lane",
          "evidence_class": "derived",
          "detail": "verify"
        }
      ],
      "replay": {
        "status": "satisfied"
      }
    }
  }
}

The important field is merge_check_id.

It is Ota's stable identity for the required verification lane. Provider check names and workflow file layout can change without forcing downstream consumers to infer lane identity from display text.

The verdict also carries its basis and replay posture. A merge decision should not be an unexplained boolean.

projected Does Not Mean Provider-Enforced

This is an important honesty boundary.

state: projected means Ota has derived the required lane from contract truth. It does not mean:

  • GitHub branch protection requires that check
  • every provider workflow is aligned
  • the provider executed the lane successfully
  • deployment policy was satisfied

Ota must not claim provider enforcement merely because it knows what the contract requires.

When Ota establishes a mismatch between the contract and recovered CI workflow truth, the state can become drift_detected. The corresponding lane becomes blocking and cites the drift basis.

That distinction keeps three layers separate:

  • contract projection: what the repo requires
  • provider wiring: how CI currently invokes verification
  • merge enforcement: what the provider or organization actually requires before merge

Turn Drift Into A Pull-Request Gate

Structured output is useful, but teams should not have to remember to run the comparison manually.

The Ota GitHub Action supports an opt-in drift gate:

.GITHUB/WORKFLOWS/CONTRACT-DRIFT.YMLyaml
name: Contract-to-CI drift on:  pull_request: permissions:  contents: read jobs:  contract-ci-drift:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v4      - name: Enforce contract-to-CI alignment        uses: ota-run/action@v1        with:          command: doctor          source: contract          fail-on-ci-drift: true          comment-pr: false

fail-on-ci-drift is deliberately opt-in. With command: doctor, it fails when Ota establishes contract-owned CI bootstrap or verification drift through the canonical merge-gate and drift findings.

It does not turn every ordinary Doctor warning into CI drift.

For stricter supply-chain reproducibility, pin third-party Actions to reviewed immutable revisions under your organization's dependency policy. The example uses the public major channel for readability.

A Live Deliberately Failing Example

Kylrix PR #1 demonstrates the boundary directly.

Its normal verification lanes are green:

  • Ubuntu native SQLite verification
  • macOS native SQLite verification
  • Windows native SQLite verification
  • Ubuntu container verification

The dedicated Contract-to-CI drift gate is intentionally red.

The pull request reproduces a realistic governance failure: workflow-owned Ota bootstrap truth duplicates and diverges from the contract instead of consuming agent.bootstrap.ota.source.

That result is more useful than making the whole matrix red. It proves that application verification can succeed while the repository's execution-governance wiring has still drifted.

The gate names the governance problem instead of disguising it as an unrelated test failure.

What Ota Should Own

Ota should own:

  • the canonical verification task and workflow
  • stable merge-lane identity
  • contract-to-CI drift evaluation
  • machine-readable blocking and decision basis
  • contract-owned bootstrap source
  • receipts and proof expectations attached to the selected lane

The CI provider should continue to own:

  • event triggers and schedules
  • permissions and credentials
  • runner labels and infrastructure
  • environments and deployment approvals
  • provider-specific notifications
  • unrelated build, release, and delivery jobs

This is not Ota trying to become another CI language. It is Ota making the execution-governance slice portable and explicit.

What The Gate Still Does Not Prove

A green contract-to-CI drift gate does not prove the whole repository is ready.

It does not prove:

  • that branch protection is configured correctly
  • that the required provider job actually ran on every relevant event
  • that runtime proof established every application invariant
  • that secrets, deployments, and external systems are healthy
  • that a maintainer's contract claim is correct merely because it is internally consistent

Those are separate governance and proof questions.

The value of the merge gate is narrower and concrete: it prevents CI verification and bootstrap truth from silently diverging from the repository contract where Ota has enough evidence to establish that drift.

Start With One Required Lane

The smallest useful adoption path is:

  1. Declare one canonical workflow with intent: ci_verification.
  2. Run ota doctor --json and inspect required_verification_lanes and merge_gate.
  3. Reconcile any established workflow drift.
  4. Add the dedicated fail-on-ci-drift pull-request check.
  5. Make that named check required through your provider's branch-protection policy.

That final provider configuration matters. Ota emits the governance truth and the check result; GitHub or another merge chokepoint decides whether contributors can route around it.

Use the public references for the exact shipped behavior:

The Broader Point

A repository contract becomes valuable at merge time when it stops being another file reviewers are expected to remember.

Ota turns declared verification truth into stable lane identity, compares it with recoverable CI wiring, and emits a machine-readable verdict that a mandatory provider check can enforce.

The contract is the specification. The merge gate is one enforcement point. Keeping those roles separate is how Ota centralizes governance without creating another source of CI truth.