Skip to content

Thread ETags, stagger sweep bursts, and attribute budget consumption - #32

Merged
ewhauser merged 1 commit into
mainfrom
refresh-etags-attribution
Aug 4, 2026
Merged

Thread ETags, stagger sweep bursts, and attribute budget consumption#32
ewhauser merged 1 commit into
mainfrom
refresh-etags-attribution

Conversation

@ewhauser

@ewhauser ewhauser commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Fixes #28 — the three companion reductions to #25/#26/#27 from the rate-limit incident.

  • ETags: PR metadata/files/check-runs refreshes send persisted If-None-Match; 304s reset endpoint freshness without rewriting state, with a validator CAS rejecting late-stale responses (C-C2 interleaving test). C-B4-observable, zero-cost budget accounting verified.
  • Burst smoothing: bounded enqueue-time jitter on sweep deadlines, clamped inside the C-R1 envelope (0.95B < B); hard deadlines and existing bound tests unchanged; River unique-key coalescing preserved.
  • Attribution: per-request budget counter (auth context × endpoint family × outcome, bounded cardinality) on the gate's public RequestHook seam — deliberately composed against Separate rate-budget accounting for App-JWT and installation-token requests #25's restructure; collector-test-pinned, documented in ops/DASHBOARD.md.

Built and adversarially reviewed by paired Codex sol-xhigh agents in a dedicated worktree (parallel with #25/#26/#27). Full gate green locally.

🤖 Generated with Claude Code

Three companion reductions from the 2026-08-04 rate-limit incident,
where check-runs, PR metadata, and PR files were the largest 403
categories after CODEOWNERS and a single C-R1 sweep enqueued ~1,300
refreshes at once:

Conditional requests: the REST refresh paths for PR metadata, files,
and check runs now send persisted ETags as If-None-Match. A 304 is a
confirmed observation only when its validator still belongs to the
current endpoint representation -- it resets that endpoint's freshness
clock without rewriting entity state, and a validator compare-and-set
rejects a late stale response arriving after a newer write, keeping
C-C2 intact under interleaving (tested). 304s flow through C-B4
accounting with correct zero-cost budget header handling.

Burst smoothing: sweep refresh deadlines get bounded jitter applied at
enqueue (River unique-key coalescing preserved), clamped so the latest
enqueue plus completion headroom stays inside the C-R1 staleness bound
(0.95B < B); hard deadlines remain last_checked_at + B and the
existing bound tests pass unchanged.

Attribution: the budget gate exports a per-request counter labeled by
auth context, endpoint family, and outcome (200/304/403/error) --
bounded cardinality, no raw paths -- built on the gate's public
RequestHook seam so it composes with #25's per-context budget
restructure. Collector shape is test-pinned and the PromQL is
documented in ops/DASHBOARD.md, turning the next incident's
attribution from hours of 403 sampling into one query.

Fixes #28

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ewhauser
ewhauser force-pushed the refresh-etags-attribution branch from 7647511 to dbe1864 Compare August 4, 2026 21:33
@ewhauser
ewhauser merged commit a2fee92 into main Aug 4, 2026
5 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.

Refresh fan-out lacks conditional-request discipline and burst smoothing; budget lacks per-endpoint attribution

1 participant