Found by deep-audit round 6 against the shipped v0.6.3.
isThrottled() matches against the log-shaped body — the one already collapsed and capped at 512 chars — so a throttle whose wording sits past the cap is not recognized as a throttle at all. The consequence is larger than losing the 30s floor: the call fails fast with no retry, which is the pre-#495 behaviour this code exists to prevent. Probe: an 884-character body carrying the wording after the cap yields isThrottled=false.
GitHub's real responses put the message first, so this is latent rather than live — but the coupling is fragile, and a body with headers or a long documentation_url ahead of the message would trip it.
Fix direction: classify from the raw body (bounded to a sane maximum) and keep the capped form for logging only.
Also filed here as related robustness: an out-of-range x-ratelimit-reset throws DateTimeException out of GitHubWriteRetry.call, which callers do not catch — they expect WebApplicationException. Pre-existing, and a malformed header from an intermediary is enough to trigger it.
Proof: audit report AUDIT6-A (findings A5, A8).
Found by deep-audit round 6 against the shipped v0.6.3.
isThrottled()matches against the log-shaped body — the one already collapsed and capped at 512 chars — so a throttle whose wording sits past the cap is not recognized as a throttle at all. The consequence is larger than losing the 30s floor: the call fails fast with no retry, which is the pre-#495 behaviour this code exists to prevent. Probe: an 884-character body carrying the wording after the cap yieldsisThrottled=false.GitHub's real responses put the message first, so this is latent rather than live — but the coupling is fragile, and a body with headers or a long
documentation_urlahead of the message would trip it.Fix direction: classify from the raw body (bounded to a sane maximum) and keep the capped form for logging only.
Also filed here as related robustness: an out-of-range
x-ratelimit-resetthrowsDateTimeExceptionout ofGitHubWriteRetry.call, which callers do not catch — they expectWebApplicationException. Pre-existing, and a malformed header from an intermediary is enough to trigger it.Proof: audit report AUDIT6-A (findings A5, A8).