Skip to content

Retract the path-dependent bypass claim: it was one refusal, generalised - #47

Merged
404SecNotFound merged 1 commit into
mainfrom
claude/cohaera-bypass-correction
Aug 30, 2026
Merged

Retract the path-dependent bypass claim: it was one refusal, generalised#47
404SecNotFound merged 1 commit into
mainfrom
claude/cohaera-bypass-correction

Conversation

@404SecNotFound

Copy link
Copy Markdown
Owner

What this changes, and why

#46 published a wrong finding and it is on main. This retracts it in place rather than quietly editing it away. Docs only — docs/OUTSTANDING.md.

#46 asserted, under a capitalised heading, that the ruleset bypass does not apply to the REST merge endpoint. It does. The claim rested on a single 405.

The evidence that settles it

# event evidence
1 PUT /repos/{owner}/{repo}/pulls/44/merge405 Pull Request is not mergeable ruleset active, 0 approvals
2 The same call, minutes later → {"merged": true, "sha": "a52da61"} a52da61 is the commit on main
3 The ruleset was active across both set active 2026-08-22T13:34:12Z; first disabled again 2026-08-30T04:19:19Z; merge committed 2026-08-30T03:39:27Z

Same endpoint, same actor, same ruleset state. Refused once, succeeded once — so the 405 was transient, not structural.

The leading explanation is GitHub's asynchronous mergeability recomputation: the ref had just been force-pushed, mergeable is computed in the background, and the merge endpoint answers 405 while it is null, not only when it is false. That is recorded as the leading explanation, not as established fact — it has not been confirmed against GitHub's implementation, and asserting it would repeat the error being corrected.

The corrected route table

merge route under an active ruleset with 0 approvals
REST PUT /pulls/{n}/merge works — observed on #44, #45, #46; one earlier 405 on a freshly force-pushed ref
Web UI merge button untested — believed to work, never actually the route used here
gh pr merge --admin not tested — its one success was under enforcement: disabled, where the flag is a no-op

Note the middle row also changed: #46 recorded the UI as "observed to work, this is how #44 landed". It is not how #44 landed. #44 landed via REST.

A second correction, same root

Two commits were described on that page and in PR descriptions as "missed by the squash". They were not. Both were pushed to branches whose PRs had already merged#44 merged at 03:39:27Z and the follow-up was pushed after it. Nothing dropped them; they went to a dead ref.

So the fix is not a convention about pushing relative to CI, which is what #46 proposed. It is: check whether the PR is still open before pushing to its branch.

Evidence

  • The defect was reproduced first — the retraction is derived from the merge response and commit timestamps quoted above, all re-read from the API rather than from session memory.
  • I mutated the fix — n/a, no executable change. Docs only.
  • python -m pytest tests/ -q passes.
  • python tests/test_evasion.py — 34/34.
  • ruff check src tests eval tools passes.
  • python tools/readme_facts.py --check passes — no count moved.
  • python tools/verify.py16 passed, 0 failed, 0 not evaluated.

If this changes detection / an evasion

  • n/a for both — documentation only, no src/ changes.

Anything a reviewer should push back on

  • The wrong claim is left visible rather than deleted. The entry now carries the claim, the refutation, and what the mistake was. That is deliberate and consistent with how PRIOR-ART.md handles the claims research retired — but it makes the entry longer again, and a reasonable reviewer could prefer a clean replacement with the history in the commit message only.
  • The transient-405 explanation is unconfirmed. It fits every observation and I could not verify it against GitHub's behaviour. If you would rather the page said only "refused once, succeeded once, cause unknown", that is defensible and one edit.
  • This is the third correction in this area in one session — the actor id, then the path-dependence, now the retraction. The pattern is a claim published from one observation. Worth noting that the underlying A8 configuration has been right throughout; only the documentation about how to operate it has been wrong.

Generated by Claude Code

#46 asserted that the ruleset bypass does not apply to the REST merge
endpoint, under a confident heading, on the strength of a single 405. That
is wrong and it is now on main, so this retracts it in place rather than
quietly editing it away.

The evidence that settles it:

  PUT /repos/{owner}/{repo}/pulls/44/merge -> 405, ruleset active, 0 approvals
  the same call minutes later            -> {"merged": true, "sha": a52da61}
  a52da61 is the commit on main, committed 2026-08-30T03:39:27Z
  ruleset was active from 2026-08-22T13:34:12Z until 2026-08-30T04:19:19Z

Same endpoint, same actor, same ruleset state; refused once, succeeded once.
The 405 was transient. The leading explanation is GitHub's asynchronous
mergeability recomputation -- the ref had just been force-pushed, and the
merge endpoint answers 405 while mergeable is null, not only when it is
false. Recorded as the leading explanation, not as established fact, because
it has not been confirmed against GitHub's implementation.

The mistake is the reusable part and is written down as such. One negative
result was treated as a property of the system instead of as a measurement
that might not repeat, and the claim was published with a heading in capital
letters. The check that would have caught it was running the same call
twice, which cost nothing. This happened inside an entry whose own subject
is not substituting a report for an observation.

Also corrects a second claim with the same root. Two commits were described
as "missed by the squash". They were not: both were pushed to branches whose
pull requests had already merged. Nothing dropped them. The fix is to check
whether the pull request is still open before pushing, not a convention
about pushing relative to CI.

Docs only. No count moved.
@404SecNotFound
404SecNotFound merged commit 65e6ce9 into main Aug 30, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant