Skip to content

A projection that stops being applied turns a build red, and a gate that cannot reach GitHub reports that it cannot rather than passing

The neighbouring claim — [GitHub milestones and issues are generated from the canonical

declared statusdeclared status: guaranteed Declared deterministic and blocking, implemented, and naming the behavioural test that is to prove it. Whether a recorded run supports it is the evidence verdict, shown beside it.

recorded evidencerecorded evidence: not run Declared guaranteed, and not supported by a recorded run: the test is named, and no passing run of the current inputs is recorded. how evidence is recorded

The adapter has exited 11 on drift since it was written and nothing called it, so the projection decayed to a tenth of the model over five days with every build green. The gate refuses behind, edited, conflict, unmanaged, state and milestone outright, and ratchets the backlog of unprojected records against .ai/repo/ci/github-drift-baseline.txt, which may fall and may never rise. The one drift it reports without refusing is the drift a head or a young landing made itself, which projected-record-edit-is-landable covers.

What it means

The neighbouring claim — GitHub milestones and issues are generated from the canonical model — is about what scripts/github-sync renders and what it refuses. It says nothing about whether GitHub has actually received any of it. This claim is the other half: that the two agree now, and that a build fails when they stop agreeing.

How it works

scripts/ci/github-check reads the remote and classifies every record. It applies two tolerances rather than one.

Refused outright, from the first run:

statewhat it means
behinda canonical record moved and nobody projected it
editeda person rewrote a generated region
conflicta person rewrote it and the record has moved since
unmanageda remote issue claims a canonical id this repository does not have
statethe remote's open/closed disagrees with the derived status
milestonethe remote's milestone assignment disagrees

Four of those states are what an apply writes: behind, state, milestone, and the closed the adapter reports beside state when GitHub is the closed side. They are reported as PENDING and not refused in two cases only: for the records a head changed since its merge base, and on the trunk for the records that changed in a landing younger than a declared window. That is a claim of its own, projected-record-edit-is-landable. On every other record they are refused, and past the window the trunk is refused for all of them.

Ratcheted against .ai/repo/ci/github-drift-baseline.txt:

statewhat it means
missinga canonical record with no counterpart on GitHub
adopta counterpart carrying no identity marker

The baseline may fall and may never rise. Writing it is a deliberate act, in the same idiom .ai/repo/claim-proof-baseline.txt already uses for the rules and claims that name nothing a machine can run.

A gate that cannot reach the remote — no gh, no token, no permission — exits 12 and names which. It never exits clean.

How to see it

scripts/ci/github-check                   # 0 in sync, 10 findings, 12 the gate cannot run
scripts/ci/github-check --write-baseline  # record today's backlog as the ceiling, deliberately
scripts/github-sync --plan                # offline: what an apply would create or change

Why it is a separate claim

Because the first claim was true and green for five days while the thing it describes had stopped happening.

--check has exited 11 on drift since the adapter was written. Nothing called it: scripts/ci/core-check ran --plan and --render, which prove a projection can be produced. The projection was applied once, on 2026-09-04, and then the model grew from 19 records to over 200 while GitHub kept the 19. Measured at 867f3a9: 200 drift findings.

All eight projected milestones were in sync throughout, because milestones are few and were touched by hand — so the surface a person looks at was the surface that still agreed. That is what a claim citing a script that exists, rather than a gate that runs, buys you.

What it does not cover

This gate applies nothing; it proves agreement. Since 2026-10-12 the apply is a consequence of the landing (.github/workflows/github.yml, project.the-projection-is-applied-at-landing), and a person's scripts/github-sync --apply is the fallback. The gate's baseline is still lowered by a person. The baseline is a ceiling, and nothing lowers it by itself: on 2026-10-10 it read 192 missing while GitHub lacked 3 records, so a new record counts as missing and passes until somebody writes the baseline down.

Nor does the gate judge the model. It says which of the two sides moved, not whether the canonical records describe the right work — that is the plan's business. And it decides nothing it cannot measure: with no gh, no token or no permission it exits 12 naming which, rather than a green build that read nothing.

Evidence

test/cases/97_github_gate.sh drives every half over a fixture repository with a fixture remote, offline: a record whose canonical text moved fails outright, a record added to the model and never projected breaks the ratchet, a backlog at its baseline passes, an edited region and an unmanaged remote issue are refused, and a gate with no baseline refuses to guess one. test/cases/45_github_projection.sh proves the six states it reads. test/cases/1038_a_head_is_judged_against_what_it_changes.sh proves which drift is pending and that everything else is still refused.

The rule is project.github-projection-gated@1.

Detail rendered from docs/claims/github-projection-gated.md.

From the statement to the proof

  1. 1 · the public statement

    A projection that stops being applied turns a build red, and a gate that cannot reach GitHub reports that it cannot rather than passing

    Made on Plan.

  2. 2 · the canonical claim

    github-projection-gateddeclared status: guaranteed in docs/CLAIMS.yaml

    Defined in read it on this site · docs/PLANNING.md

  3. 3 · the implementation

    scripts/ci/github-check

  4. 4 · the test and the scenarios

    Test: test/cases/97_github_gate.sh

  5. 5 · the recorded runs

    recorded evidence: not run how evidence is recorded

Verify it yourself

The test runs in a disposable temporary repository and asserts the behaviour, not a string in the source.

from a clone of the repository
bash test/run.sh 97_github_gate

Where this claim is used

responsibilities it covers

Related claims same implementation

Searches the titles and descriptions of every page this site publishes.