Skip to content

I3200 — The trunk's protection is compared with the CI model, and a drift is a finding that names the change

Declare the aggregate verdict check once in .ai/repo/ci/gates.yaml, then compare the required checks the last forge observation read for master with it, and report a missing, extra or unread requirement as a finding with the idempotent gh command that would fix it, from the recorded observation and without reaching the network; scripts/ci/release-verdict reads the same declaration.

BLOCKED wave 2 · p1 · implementation profile · parallel safe

Part of finished-work-reaches-a-verified-release — Finished work reaches a verified release at the pace it is finished.

Blocked. This issue cannot start until I2709 is done. The status is derived from that, not declared.

Objective

Declare the aggregate verdict check once in .ai/repo/ci/gates.yaml, then compare the required checks the last forge observation read for master with it, and report a missing, extra or unread requirement as a finding with the idempotent gh command that would fix it, from the recorded observation and without reaching the network; scripts/ci/release-verdict reads the same declaration.

Why

On 2026-09-11 GitHub reported master protected:false with no required checks while PR #207 recorded a merge made over red CI; the owner then made landing integrity the first P0 (c113#10). On 2026-10-18 an audit still could not list master's required checks (c295#3). Since then prs refresh reads the protection, but only the drain uses it, and only to refuse a base that requires nothing. It extends milestone architecture-is-enforced. Sources: chatgpt-majordomus:c112#3, chatgpt-majordomus:c113#10, chatgpt-majordomus:c130#10, chatgpt-majordomus:c295#3, chatgpt-majordomus:c112#2.

Current state

apps/majordomus-cli/src/integration/forge.rs reads branch protection and rulesets into the observation; classify.rs turns an empty requirement into ReasonCode::NoRequiredChecks for each pull request. Nothing compares the names with the CI model, doctor does not read the observation, and I2282 (READY) covers only the record pull request's dispatched verdict. On master 707a04c7ce8 gates.yaml declares no aggregate verdict check: the name `ci` lives in validate.yml's job id, release-verdict's RELEASE_VERDICT_CHECK default and classify.rs fixtures. .ai/repo/ci/queue.yaml says the scheduled token is read-only and cannot read the protection on the runner. I2709 (READY, M004) carries the red-trunk carrier rule with red_trunk_holds_the_landing_claim_test, which no case or test file implements yet.

Desired state

majordomus prs status and doctor both carry one protection finding derived from the observation: required checks equal to the CI model's verdict check, or the difference named with the command that repairs it; an unread protection is unknown, never a pass.

Scope

  • apps/majordomus-cli/src/integration/forge.rs
  • apps/majordomus-cli/src/integration/classify.rs
  • lib/doctor.sh
  • docs/INTEGRATION.md
  • .ai/repo/ci/gates.yaml
  • scripts/ci/release-verdict

Out of scope

  • Changing the protection from the tool
  • Reading the forge from doctor

Dependencies

Acceptance criteria

  • A fixture observation whose required checks omit the CI model's verdict check yields a finding naming the check and the gh command that adds it
  • An observation that could not read the protection yields unknown, never a pass or an empty list
  • The check name compared is read from .ai/repo/ci/gates.yaml, not written in the code
  • I3200 covers a-red-trunk-holds-the-landing only together with I2709's red_trunk_holds_the_landing_claim_test; its own case_protection_drift_is_a_finding proves the protection half alone
  • gates.yaml declares the aggregate verdict check once; the protection comparison and scripts/ci/release-verdict (RELEASE_VERDICT_CHECK default) both read that declaration
  • On the scheduled runner the protection finding is reported as unknown by design (.ai/repo/ci/queue.yaml: read-only token); the live half is recorded as evidence from a prs refresh run with a token that can read the protection, naming the observation's time

Validation

  • majordomus plan validate
  • cargo test --manifest-path apps/majordomus-cli/Cargo.toml --lib integration::

Evidence required

  • case_protection_drift_is_a_finding

Evidence

None recorded. Every token above needs a command or an artifact behind it before this issue can be completed; narrative is refused.

Timeline

started
—
verified
—
completed
—

Those three fields, the evidence above and the state of the dependencies are all the status is made of. There is no status field to disagree with them.

Canonical record: .ai/repo/project/issues/I3200.yaml. Read it back with majordomus plan show I3200.

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