Adds CLAUDE.md, the first agent-facing delivery doc in this repo, and records in DECISIONS-LOG.md what going through the PR flow actually turned up.
The merge gate does not exist. Verified against the live Gitea API, not inferred
from the docs:
branch_protections returns [] — main is protected: false, enable_status_check: false, status_check_contexts: [], required_approvals: 0, user_can_push: true
Zero Actions runners registered at repo, org and site level
DECISIONS-LOG 2026-08-31 asserts a "required status check" and runner incluster-dind "online". Both are false of the live system. PR #1 — the first PR
this repo has ever had — has two contexts sitting pending with nothing to execute
them.
CLAUDE.md states the branch → PR → gate → approval → merge rule alongside the
honest fact that enforcement is currently weaker than the rule, so agents follow the
rule rather than what they can get away with. It also carries the toolbox gate
invocation, the two git-worktree workarounds, the rc 0/1/3 contract, and secret
handling.
Ordering trap, called out in both files: do not enable a required status check
before a runner is live — it deadlocks every PR permanently, including the one that
would fix it. Same hazard applies to gate.yml's conformance job, which is if: false yet still publishes a context.
Gate: ./ci/gate.sh in the pinned toolbox — MERGE GATE: PASS, rc 0, 74s, with
spec-immutability included (spec repo mounted as a sibling).
Adds `CLAUDE.md`, the first agent-facing delivery doc in this repo, and records in
`DECISIONS-LOG.md` what going through the PR flow actually turned up.
**The merge gate does not exist.** Verified against the live Gitea API, not inferred
from the docs:
- `branch_protections` returns `[]` — `main` is `protected: false`,
`enable_status_check: false`, `status_check_contexts: []`, `required_approvals: 0`,
`user_can_push: true`
- **Zero Actions runners** registered at repo, org and site level
DECISIONS-LOG 2026-08-31 asserts a "required status check" and runner
`incluster-dind` "online". Both are false of the live system. PR #1 — the first PR
this repo has ever had — has two contexts sitting `pending` with nothing to execute
them.
`CLAUDE.md` states the branch → PR → gate → approval → merge rule *alongside* the
honest fact that enforcement is currently weaker than the rule, so agents follow the
rule rather than what they can get away with. It also carries the toolbox gate
invocation, the two git-worktree workarounds, the rc 0/1/3 contract, and secret
handling.
**Ordering trap, called out in both files:** do not enable a required status check
before a runner is live — it deadlocks every PR permanently, including the one that
would fix it. Same hazard applies to `gate.yml`'s `conformance` job, which is
`if: false` yet still publishes a context.
Gate: `./ci/gate.sh` in the pinned toolbox — **MERGE GATE: PASS, rc 0, 74s**, with
spec-immutability included (spec repo mounted as a sibling).
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Going to land the plex claim wiring through the documented PR flow surfaced that
the flow has never run. PR #1 is the first pull request this repo has ever had.
Verified against the live Gitea, not inferred from the docs:
* branch_protections is [] -- main is protected:false, enable_status_check:false,
status_check_contexts:[], required_approvals:0, user_can_push:true
* ZERO Actions runners registered at repo, org and site level
DECISIONS-LOG 2026-08-31 asserts a "required status check" and a runner
"incluster-dind online". Both are false of the live system. The gate is neither
enforced nor able to run, and that went unnoticed because the log claimed
otherwise -- the same fail-open class as the two holes found on 2026-09-18.
Adds CLAUDE.md, the first agent-facing delivery doc here: the
branch -> PR -> gate -> approval -> merge rule, stated alongside the honest fact
that enforcement is currently weaker than the rule, so agents follow the rule
rather than what they can get away with. Carries the toolbox gate invocation, the
two git-worktree workarounds, the rc 0/1/3 contract, and secret handling.
Records the ordering trap: enabling a required status check before a runner exists
deadlocks every PR permanently, including the one that would fix it.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Gitea repo settings live in its own database, not in a manifest Flux reconciles, so
they are drift-prone and invisible to the conformance gate -- which is how main came
to accept direct pushes while the log recorded it as protected.
Adds infra/gitea/branch-protection.sh (blocks direct pushes to main) and a README
carrying the measured before-state and the ORDER the remaining steps must happen in.
The script deliberately leaves enable_status_check:false and required_approvals:0.
Both would deadlock today: there is no runner to satisfy a required context, and the
only human account is not yet a repo collaborator, so no one could supply an approval.
The README sequences both.
It prints a push probe to run afterwards. The API response is not proof -- Gitea may
let site admins bypass protection, and that has to be observed, not assumed.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
No runner is registered at repo, org or site level, so gate.yml has never executed.
PR #1 sat pending for 30.6 minutes across 122 polls and never reported. Requiring the
gate as a status check in that state would lock the repo permanently.
Adds runner-token-rotate.sh: mints a fresh instance-level registration token from the
Gitea API and writes it into the SOPS secret via sops set, without ever printing the
value.
Records the likely root cause, which a new token alone does NOT fix. act_runner
registers once and persists its identity in /data/.runner on the act-runner-data PVC.
If Gitea no longer holds a matching runner row, the pod starts, sees .runner, SKIPS
registration entirely, and polls with an identity Gitea does not recognise. Symptom:
zero runners, pod running, nothing obviously broken. Clearing the PVC is what forces a
genuine re-registration.
The README now sequences runner-first, enforcement-second, and requires CONFIRMING the
runner reports online rather than assuming it. That assumption is the whole defect:
DECISIONS-LOG recorded the runner as online on 2026-08-31 and nobody checked since.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Adds
CLAUDE.md, the first agent-facing delivery doc in this repo, and records inDECISIONS-LOG.mdwhat going through the PR flow actually turned up.The merge gate does not exist. Verified against the live Gitea API, not inferred
from the docs:
branch_protectionsreturns[]—mainisprotected: false,enable_status_check: false,status_check_contexts: [],required_approvals: 0,user_can_push: trueDECISIONS-LOG 2026-08-31 asserts a "required status check" and runner
incluster-dind"online". Both are false of the live system. PR #1 — the first PRthis repo has ever had — has two contexts sitting
pendingwith nothing to executethem.
CLAUDE.mdstates the branch → PR → gate → approval → merge rule alongside thehonest fact that enforcement is currently weaker than the rule, so agents follow the
rule rather than what they can get away with. It also carries the toolbox gate
invocation, the two git-worktree workarounds, the rc 0/1/3 contract, and secret
handling.
Ordering trap, called out in both files: do not enable a required status check
before a runner is live — it deadlocks every PR permanently, including the one that
would fix it. Same hazard applies to
gate.yml'sconformancejob, which isif: falseyet still publishes a context.Gate:
./ci/gate.shin the pinned toolbox — MERGE GATE: PASS, rc 0, 74s, withspec-immutability included (spec repo mounted as a sibling).
Co-Authored-By: Claude Opus 5 (1M context) [email protected]
🤖 Generated with Claude Code