From 234cc6a71ab6a840b2fd590c3706785ccc684864 Mon Sep 17 00:00:00 2001 From: Keith Jackson Date: Tue, 29 Sep 2026 01:07:13 -0500 Subject: [PATCH] docs(gitea): a skipped job reports SUCCESS, not pending -- correct the deadlock claim The runner came up on 2026-09-29 and the first CI jobs this repo has ever run went green, which falsified a claim merged in #2. MEASURED: gate / gate (pull_request) success 1m58s (PR 1), 1m34s (PR 2) gate / gate (push) success 1m32s (PR 2 only) gate / conformance (pull_request) success "Has been skipped" #2 said listing the conformance context as a required check would deadlock every PR, because the job is `if: false` and never runs. That is wrong. Gitea reports a skipped job as SUCCESS. Requiring it would not deadlock anything -- it would pass VACUOUSLY, forever, while nothing ran. The conclusion is unchanged (never require it) but the reason inverts, and the corrected reason matters more: under HARD RULE 4 a permanently-green check that verifies nothing is worse than a deadlock. A deadlock is loud. This is the exact fail-open shape the 2026-09-18 audit and this one both keep finding. Also records that the (push) contexts only appear for branches matching gate.yml's push trigger -- feature/**, fix/**, docs/**, chore/** -- and NOT feat/**, which is why PR 1's feat/ branch produced only pull_request contexts. Require the pull_request context alone, or PRs from non-matching prefixes never satisfy the rule. CLAUDE.md's enforcement table is updated: the runner half is genuinely fixed and observed green, the branch-protection half is not. Adds the warning that a green tick is not by itself evidence that anything ran. Co-Authored-By: Claude Opus 5 (1M context) --- CLAUDE.md | 16 +++++++++------- infra/gitea/README.md | 29 ++++++++++++++++++++++++++--- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index c59709d..3abb825 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -31,17 +31,19 @@ Verified against the live Gitea on 2026-09-29: |---|---| | `main` protected, direct push rejected | **No branch protection.** `protected: false`, `user_can_push: true` | | PR blocked until the gate passes | **`enable_status_check: false`**, `status_check_contexts: []` | -| Gate runs on every PR | **No Actions runner is registered** (repo, org and site level all report zero) | +| Gate runs on every PR | **Fixed 2026-09-29.** Runner `incluster-dind` is online; `gate / gate (pull_request)` runs and passes in ~1m30s–2m | | Approval required before merge | **`required_approvals: 0`** | So nothing mechanically stops you from pushing to `main` right now. **That is a gap -being closed, not permission.** `DECISIONS-LOG.md` (2026-08-31) claims the gate is a -"required status check" with a runner online; that claim is not true of the live -system, which is how this went unnoticed. +being closed, not permission.** `DECISIONS-LOG.md` (2026-08-31) claimed the gate was a +"required status check" with a runner online; neither was true, which is how this went +unnoticed for a month. The runner half is now genuinely fixed and observed green. The +protection half is not — see `infra/gitea/`. -**Consequence for you:** because CI cannot run, the **local toolbox gate is the only -real gate**. Run it and quote its numbers in your report. Never describe a PR as -"green" on the strength of CI that did not execute. +**Consequence for you:** CI now runs, but it does not yet *block* anything. Always run +the toolbox gate yourself and quote its numbers. Never describe a PR as "green" on the +strength of a check you have not seen report — and note that a **skipped** Gitea job +reports as `success`, so a green tick is not by itself evidence that anything ran. ## 3. Gate before you push diff --git a/infra/gitea/README.md b/infra/gitea/README.md index d8655e0..4b9dbf7 100644 --- a/infra/gitea/README.md +++ b/infra/gitea/README.md @@ -54,6 +54,29 @@ commands. 4. Add the human reviewer as a repo collaborator, then raise `required_approvals` to 1. > **Do not do step 3 before step 1.** A required status check with no runner leaves every -> PR permanently pending — including the PR that would fix it. The same applies to -> `gate.yml`'s `conformance` job: it is `if: false` and never runs, yet still publishes a -> `gate / conformance (pull_request)` context. Never list that one as required. +> PR permanently pending — including the PR that would fix it. That half is measured: PR #1 +> sat `pending` for 30.6 minutes across 122 polls with no runner registered, and never +> reported. + +### Measured, once the runner came up (2026-09-29) + +The first CI jobs this repo ever ran, on PR #1 and PR #2: + +| Context | Result | Time | +|---|---|---| +| `gate / gate (pull_request)` | success | 1m58s (PR #1), 1m34s (PR #2) | +| `gate / gate (push)` | success | 1m32s (PR #2 only) | +| `gate / conformance (pull_request)` | **success — "Has been skipped"** | — | + +**Require `gate / gate (pull_request)`. Do NOT require either `conformance` context — +but not for the reason an earlier draft of this file gave.** A skipped Gitea Actions job +does not hang a status check: Gitea reports it as **`success`** with the description +"Has been skipped". So requiring it would not deadlock anything — it would pass +*vacuously*, every time, forever, while nothing ran. Under HARD RULE 4 that is worse than +a deadlock: a deadlock is loud, a permanently-green check that verifies nothing is +exactly the fail-open shape this repo keeps finding. + +The `(push)` contexts appear only for branches matching `gate.yml`'s push trigger +(`feature/**`, `fix/**`, `docs/**`, `chore/**`). `feat/**` is **not** in that list, which +is why PR #1's `feat/` branch produced only `pull_request` contexts. Require only the +`pull_request` context, or PRs from non-matching prefixes will never satisfy the rule. -- 2.54.0