charter template: test a refusal, and do not count a transport failure as one

Propagated from claude-bridge CLAUDE.md. The step 8 refusal paragraph told a lead
what to do when the forge refuses a merge, but not how to establish that it did.

Both halves came from the fleet01 lead, measured on akb/kb on 2026-09-08 UTC.

First: it re-ran the all-zeroes head_commit_id probe after the operator granted
merge rights, and got HTTP 409 'head out of date' where the same request gave 405
'User not allowed to merge PR' on 2026-09-06. A 409 is payload validation, which
is only reachable after the permission gate, so the grant took. The lead reports
the repository permissions object did not change at all across that flip -- still
admin:false, push:true, pull:true. I did not check that object myself; my forge
token is a different identity and would read a different one. Merge rights on a
protected branch live in branch protection, so a permissions field is wrong in
both directions and only the probe tells them apart.

Second: the lead's first probe attempt returned HTTP 000, because GITEA_HOST
already carries the scheme and a trailing slash and the URL came out as
https://https://git.ltms.dev//api/... A transport failure looks exactly like a
refusal if the test is 'not 200'. That is the trap worth naming, because the
whole point of the probe is to tell a refusal apart from everything else.

Sync check in the claude-bridge addendum reports 'in sync: True'.
Dai Ha
2026-09-09 04:08:43 +07:00
parent 474b99fb58
commit 8c2ef96184
+6
@@ -405,6 +405,12 @@ below are the procedure — run them in order, every task, not only the big ones
without having read the diff yourself. A refusal is exactly when that shortcut is tempting,
because no action is left that forces you to look, and taking it turns this step into
forwarding a reviewer's verdict — which is delegating the merge by proxy, two lines above.
**Test a refusal; do not read it off a permissions field.** A protected branch holds its merge
rights separately from the repository permissions, so that field can say yes while the merge is
refused, and still say no after a grant makes it work. Probe instead, with a request that cannot
succeed on its merits, so a rejection can only mean the refusal. Treat a transport failure as a
third answer that proves nothing: a timeout, a DNS error or a bad URL is not a refusal, and
counting it as one makes you sure of something you never measured.
**Steps 3 and 4 are separate on purpose** — spawning and sending in one loop is how parallel work
silently becomes serial, and it is the most common way this layer is wasted. For the same reason,