feat(agents): pin test requests and results to commits #2830
Open
github-sync
wants to merge 7 commits from
github/pr/2830 into main
pull from: github/pr/2830
merge into: MagicBeanDev:main
MagicBeanDev:main
MagicBeanDev:github/pr/2893
MagicBeanDev:github/pr/2890
MagicBeanDev:github/pr/2887
MagicBeanDev:github/pr/2878
MagicBeanDev:github/pr/2875
MagicBeanDev:github/pr/2874
MagicBeanDev:github/pr/2873
MagicBeanDev:github/pr/2871
MagicBeanDev:github/pr/2756
MagicBeanDev:github/pr/2897
MagicBeanDev:github/pr/2896
MagicBeanDev:github/pr/2718
MagicBeanDev:github/pr/2842
MagicBeanDev:github/pr/2691
MagicBeanDev:github/pr/2895
MagicBeanDev:github/pr/2743
MagicBeanDev:github/pr/2765
MagicBeanDev:github/pr/2708
MagicBeanDev:github/pr/2732
MagicBeanDev:github/pr/2755
MagicBeanDev:github/pr/2817
MagicBeanDev:github/pr/2876
MagicBeanDev:release-please--branches--main
MagicBeanDev:release-please--branches--main--release-notes
MagicBeanDev:github/pr/2778
MagicBeanDev:github/pr/2888
MagicBeanDev:github/pr/2866
MagicBeanDev:github/pr/2877
MagicBeanDev:github/pr/2800
MagicBeanDev:github/pr/2829
MagicBeanDev:github/pr/2850
MagicBeanDev:github/pr/2889
MagicBeanDev:github/pr/2882
MagicBeanDev:github/pr/2860
MagicBeanDev:github/pr/2849
MagicBeanDev:github/pr/2886
MagicBeanDev:github/pr/2794
MagicBeanDev:github/pr/2840
MagicBeanDev:github/pr/2834
MagicBeanDev:github/pr/2719
MagicBeanDev:github/pr/2742
MagicBeanDev:github/pr/2741
MagicBeanDev:github/pr/2820
MagicBeanDev:github/pr/2771
MagicBeanDev:github/pr/2859
MagicBeanDev:github/pr/2858
MagicBeanDev:github/pr/2823
MagicBeanDev:github/pr/2757
MagicBeanDev:github/pr/2769
MagicBeanDev:github/pr/2844
MagicBeanDev:github/pr/2843
MagicBeanDev:github/pr/2673
MagicBeanDev:github/pr/2855
MagicBeanDev:github/pr/2739
MagicBeanDev:github/pr/2807
MagicBeanDev:github/pr/2851
MagicBeanDev:github/pr/2789
MagicBeanDev:github/pr/2814
MagicBeanDev:github/pr/2818
MagicBeanDev:github/pr/2774
MagicBeanDev:github/pr/2772
MagicBeanDev:github/pr/2750
MagicBeanDev:github/pr/2786
MagicBeanDev:github/pr/2785
MagicBeanDev:github/pr/2782
MagicBeanDev:github/pr/2779
MagicBeanDev:github/pr/2775
MagicBeanDev:github/pr/2706
MagicBeanDev:github/pr/2766
MagicBeanDev:github/pr/2747
MagicBeanDev:github/pr/2759
MagicBeanDev:github/pr/2745
MagicBeanDev:github/pr/2740
MagicBeanDev:github/pr/2733
MagicBeanDev:github/pr/2725
MagicBeanDev:github/pr/2727
MagicBeanDev:github/pr/2728
MagicBeanDev:github/pr/2729
MagicBeanDev:github/pr/2721
MagicBeanDev:github/pr/2722
MagicBeanDev:github/pr/2715
MagicBeanDev:github/pr/2714
MagicBeanDev:github/pr/2707
MagicBeanDev:github/pr/2703
MagicBeanDev:github/pr/2705
MagicBeanDev:github/pr/2697
MagicBeanDev:github/pr/2679
MagicBeanDev:github/pr/2676
MagicBeanDev:github/pr/2669
MagicBeanDev:docs/what-hookshot-connects-to
MagicBeanDev:fix/hdr-encode-test
MagicBeanDev:fix/main-tests
MagicBeanDev:fix/play-cache-files
MagicBeanDev:perf/game-barrier-order
MagicBeanDev:feat/heap-lazy
MagicBeanDev:feat/texture-detail
MagicBeanDev:perf/astc-opaque-bc1
MagicBeanDev:fix/fs-dir-lock
MagicBeanDev:fix/framegen-native-kept
MagicBeanDev:fix/update-no-downgrade
MagicBeanDev:port/k10-gcn-f16-mirrors
MagicBeanDev:fix/framegen-mult-cap
MagicBeanDev:chore/release-as-2.1.1
MagicBeanDev:perf/pcache-load-switch
MagicBeanDev:fix/prepare-progress-log
MagicBeanDev:fix/update-closes-stale-game
MagicBeanDev:fix/hdr-scaled-sampled
MagicBeanDev:perf/first-start-preset
MagicBeanDev:perf/zero-upload
MagicBeanDev:fix/vcore-escape-2s
MagicBeanDev:test/fake-gh-atomic
MagicBeanDev:perf/batch-idle-flush
MagicBeanDev:test/finish-stub-a
MagicBeanDev:chore/record-2.1.0
MagicBeanDev:fix/main-red-tests
MagicBeanDev:fix/test-display-startup-driver-cache
MagicBeanDev:feat/mesh-shader-mode
MagicBeanDev:fix/menu-probes-at-startup
MagicBeanDev:fix/fps-counter-classic
MagicBeanDev:fix/test-log-batch-flake
MagicBeanDev:fix/narrow-screen-hud
MagicBeanDev:ci/prereleases
MagicBeanDev:release/v2.0.15
MagicBeanDev:hotfix/v2.0.15
MagicBeanDev:fix/present-ahead-replay
MagicBeanDev:release/v2.0.13
MagicBeanDev:fix/bracket-paths-2013
MagicBeanDev:fix/hdr-overlays-2013
MagicBeanDev:fix/fps-counter-scale-2013
MagicBeanDev:fix/stick-seen-at-rest
MagicBeanDev:hotfix/menu-fits-screen
MagicBeanDev:fix/f1-always-opens-menu
MagicBeanDev:fix/ini-keep-lines
MagicBeanDev:claude/cranky-pike-7cf247
MagicBeanDev:perf/texture-answer-flat
MagicBeanDev:fix/stamp-test-modules
MagicBeanDev:fix/appimage-fonts
MagicBeanDev:fix/display-awake
MagicBeanDev:release/v2.0.12
MagicBeanDev:fix/discord-windows
MagicBeanDev:rc/v2.0.12-tests
MagicBeanDev:fix/dlss-keep-feature
MagicBeanDev:rc/v2.0.12
MagicBeanDev:button-icons
No reviewers
Labels
Clear labels
accessibility
Barrier affecting people with disabilities
autorelease: pending
autorelease: tagged
bug
Something isn't working
dependencies
Pull requests that update a dependency file
documentation
Improvements or additions to documentation
duplicate
This issue or pull request already exists
enhancement
New feature or request
github_actions
Pull requests that update GitHub Actions code
good first issue
Good for newcomers
help wanted
Extra attention is needed
invalid
This doesn't seem right
question
Further information is requested
testing wanted
wontfix
This will not be worked on
No labels
accessibility
autorelease: pending
autorelease: tagged
bug
dependencies
documentation
duplicate
enhancement
github_actions
good first issue
help wanted
invalid
question
testing wanted
wontfix
Milestone
Clear milestone
No items
No milestone
Assignees
Clear assignees
No assignees
1 participant
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Hookshot!2830
Loading…
Reference in a new issue
No description provided.
Delete branch "github/pr/2830"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What this is for: testers and authors should be able to tell which commit a test request asks for, and whether a result covers the current pull request. This extends the queue from #2734 and #2746 without replacing its room-message format. What is measured: offline queue tests on Linux, including the old client reading new messages: 225 checks passed. The complete game-free rerun had 474 passed, 1 failed, 20 skipped; the failure is the unchanged release-script concurrency case described below. Three central tests fail against main for the missing commit tracking. The project's whole check set, both
windows-2022parts included, passed on a run on my fork before this was opened. Not measured: a live claim and result (the trial card waits for a maintainer's label), or how the Discord relay treats the added lines beyond what the trial below shows. No game or GPU is needed for this change.Refs #2797.
Problem
A request names a PR, but a PR can change while someone is building it.
On November 12, #2731's defect report named
bce3d17e. The author fixed it in309e6c35at 13:52 UTC. A test result posted at 14:43 UTC correctly named its build ofbce3d17e, but the queue had no way to distinguish that result from a test of the new head. The test remains useful evidence for its build; it is not evidence for the later fix.In
scripts/test_requests.py,cmd_requestrecorded the PR number, andreplayrecorded each result and comment link, but neither stored a commit. The existing GitHub approval response already contains the head SHA.What changed
requestreuses its one GitHub response to store the head.request --commit <sha>deliberately chooses another commit of that PR. Values must be 7–40 hexadecimal characters. A head abbreviation expands to the full head; another value is kept and called out as an explicit non-head choice. The script checks the spelling, not membership in the PR or abbreviation uniqueness. If GitHub cannot be reached, an explicit full 40-character SHA still posts, with approval and head unknown; without it, the error explains that remedy.done --commit <sha>records the actual build. Without it, the default is the commit recorded for that tester at claim time, even if the requester updated the card during the test. A result differing from the head observed at reporting time says “tested an earlier commit”. GitHub being unreachable or rate-limited never blocks recording a finished test: it writes the commit without a head and explains that the comparison was unavailable.update T-XXXX --commit <sha>is restricted to the requester and an open card. It keeps the ID, claims, results and room history. Older results stay visible with their commits, but do not satisfy the new pin or block another claim. Existing testers retain the commit they started with.listcalls the same annotation path as main, once per distinct open PR. That same answer supplies the head at no extra API cost. Waiting requests still say they need a maintainer and appear last.showchecks its one PR, andclaimalways checks approval again.done. The comment still startsTest request T-XXXX: pass|fail|mixed, followed by hardware and the commit built.No new package, shell command or platform-specific code is used by the client.
GITHUB_TOKEN, thenGH_TOKEN, remain optional. The script does not retrieve a token fromgh.Message compatibility
The original first line stays unchanged.
Commit:andHead:lines are appended after all existing lines, including request notes. For example:Old requests without these fields render exactly as before. The old client treats added request lines as notes and ignores added claim/result lines; its result URL is unchanged. The new client's per-tester commit map is separate from the old numeric claim-expiry map. An old client's result without a commit still appears, but is not credited to a known commit. Old clients ignore
updateand cannot enforce pins.The Discord relay is separate software. This repository does not build its embeds, and the relay's unknown-field handling is not documented. Loading the old client in tests proves client compatibility, not server compatibility. hckrman101, as the relay owner, should confirm that appended lines preserve the card, and that its commit display and update handling agree with the client. The guide keeps the old Discord layout and adds a separate CLI example; it does not claim the live relay already shows the new fields.
GitHub calls
For successful commands on open cards, with
Ndistinct PRs in a listing:requestlistshowclaimdonerenew,release,cancelupdateThe existing rate-limit warning remains; there are no retries. Reads still show the room record when GitHub is unavailable.
donestill posts withCommit:but noHead:and a note.requestcan also post without a successful lookup when--commitis a full 40-character SHA; otherwise it explains that a known full commit or a later retry is required. Such a card's approval stays unknown until the next successful lookup. Claiming still requires approval; the new update command requires a head check.How to try it
After the PR is pushed and approved for testing:
Build the commit printed by
claim, not whichever head a later fetch returns. Report the actual build:The requester can move the card after a fix:
Use
show T-XXXXfor a fresh single-card view orlistto refresh the queue's approval, PR state and heads together.How it was tested
Arch Linux, kernel
7.2.15-1-omarchy, Intel Core i9-13900K, Python 3.12, November 12. Base51da0464; headd22aec74. No game, GPU or window. The whole-suite receipt records load average 7.58 → 46.27; this was a correctness run, not a performance measurement. Tests used fake room/session/GitHub responses, and command tests reject unexpected HTTP calls.Focused tests and compatibility
python -I -B tests/test_test_requests.py --old-source <main-client-copy>:The old-client copy is the actual
scripts/test_requests.pyfrom main51da0464, loaded alongside the new client. It accepts the new request, claim and done, retains the exact result URL, treats the request's extra fields as notes, and ignores the unknown update action. The stored old-format card test compares its complete rendering byte-for-byte.The remaining cases cover approval and merged-PR refusals, claim renewal/expiry, explicit and default commits, malformed hex/lengths, upper-case and abbreviated commits, a requester update during an active test, old results without commit metadata, no extra request API call, equal list-call counts against the actual main client, optional-token precedence, and GitHub outages/rate limits. Both claimed/default and explicit done commits still post without Head; requests without a known full SHA fail with the remedy, while an explicit full SHA posts and remains approval-unknown until a later lookup succeeds.
The three central tests against main
The same test file with
--source <main-client-copy> --test request_head --test moved_head --test done_commitexits 1, with ordinary assertion failures rather than a missing option or import failure:All three pass in the branch run above.
Whole game-free suite
python -I -B tests/run_all.py --jobs 8, through the local idle/core-dump wrappers, with the project's pinned dependencies:Exit 1. The queue tests and tracked-Python source compilation check passed. The one failure is
tests/test_release_scripts.py::test_nightly_two_runs_at_once_end_at_the_newer_commit, subcasefirst='A':The case name and message match the known release-script race signature. That test and
scripts/release_files.share unchanged from pinned main; this is not a current-main rerun or a green-suite claim. The failure was retained, not retried away. The pre-review revision had passed475/0/20in 158 s; that earlier result is not a substitute for this rerun. The 20 skips are the runner's existing Windows/game/GPU-only declarations; none was added here.Real-room trial
One real request, made with this branch's client (
d22aec74) for this pull request: T-6BH3.The card as this branch's client shows it (
show T-6BH3):The same card as main's client (
51da0464) lists it: everything as before, with the two new lines read as notes:The Discord relay accepted the new message. The card appeared in the test-request channel like every other one (title, "Waiting for a maintainer to add the testing wanted label", the Needs line, "Pull request: #2830", T-6BH3). It does not show the commit, as expected: the relay would need its own small change for that.
Not shown yet: a live
claim,doneandupdate. The card cannot be claimed until a maintainer adds the label, so those three ran against the test room only. @hckrman101, as the relay's owner: could you confirm the relay is happy with the extraCommit:/Head:lines on claim and result messages and with the newupdateaction before this is relied on? If it is not, the fallback in Risks (the same data in the event's content, the visible text unchanged) is what I would do.Not tested
windows-2022and passed on the fork run above); the client was not used against the live room from Windows.Risks
The behaviour changes from main are limited to:
--commit. No approval rule is relaxed.updateaction moves the pin without deleting history.doneasks GitHub once to compare heads when it can; a failed lookup is only a note and never blocks the result.Plain
listkeeps main's approval display and API-call count. The relay's owner should confirm the card rendering before rollout.update. A mixed-version queue can therefore still contain results with unknown commits; these are shown as unknown, not silently assigned a SHA.Overlaps
The overlap check found three open PRs sharing an edited file; their shared hunks were read:
docs/test-requests.md:25–40on this branch (main's line 25). It adds the hardware-runner link to “You can take part…”, immediately after this change's new CLI example. Keep both; whichever lands second rebases. Its label-gated automation enforces the exact labelled commit and checks it is still the PR head before running the test: that is the automated workflow that needs an unambiguous requested/tested commit in this queue. The conflicting hunk does not implement the queue fields.AGENTS.md; merges cleanly with the request instructions.AGENTS.md; merges cleanly with the request section.Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra [email protected]
Thanks, this is a real gap (a result for a build that is no longer the head being read as a result for the fix), and the compatibility work is careful. I read the diff, no run. CI is green on
d22aec7, no conflicts with main.What I checked and found fine:
Commit:/Head:replay as before;current_resultsonly filters when the card itself has a commit, so legacy cards keep their ordering and "nobody has tested it yet".test_old_cardandtest_old_clientcover the old format, including a stored old card rendered byte for byte.pr_infourllib call that approval already used, so noghdependency and no new platform code; it works on Windows.donedegrades to a note when GitHub is unreachable,claim/updaterefuse without an answer (asclaimalready did).Points worth fixing, in order:
Stale results are not visible to a JSON reader.
current_resultsis used for sorting,claimand the "nobody has tested this commit" line, butlist --json/show --json(public(t)) return the rawresults. The /testing skill tells the agent to skip a request when its own name is inresults, "unless the PR changed". Afterupdate, an agent doing that will skip the card it should now test, because its old result is still listed. Please expose the filtered view (e.g. acurrentflag on each result, orcurrent_resultsas its own key) and word the skill step in terms of it. The same "unless the PR changed since your result" wording is still in both skills and inclaim's refusal path: with pins, a moved head without anupdatedoes not make the same pin worth retesting, so it should say "unless the card was updated to a new commit".--commitis not tied to the PR, and that sits next to the approval gate. The guide says approval keeps strangers' code off testers' PCs until someone has looked at the PR. Now any requester can pin an arbitrary 7-40 hex value, andgit checkout --detach <commit>in the testing skill will build it if it is fetchable (GitHub serves commits from other forks in the same network by SHA). The PR calls this out ("membership in the PR is not checked") but the tester side has no guard. Cheapest fix is in the testing skill: before building, check the commit is part of the PR (git merge-base --is-ancestor <commit> <PR head>, or the PR's commit list), review that commit's diff rather than the head's, and release the claim if it is not. Checking it inrequest/updatethrough the PR commits endpoint would be stronger but costs a call; I would be fine with the skill-only version.A moved head still lets the claim go through.
claimposts, prints "ask the requester to confirm", and the tester is then holding a 90 minute claim on a commit that may already be superseded. For/loop 30m /testingthere is nobody to ask.listalready shows the "head moved" line, so the skill could say to skip cards that show it unless the requester has confirmed, orclaimcould need an explicit--commitwhen the head moved. Your call, but as written an unattended agent will happily test the stale pin.requestnow needs GitHub. Before, a request posted even when GitHub was down or rate limited (60 an hour without a token, shared by an office or a CGNAT). Now it fails unless an explicit full SHA is given. The error says so, so I think that is acceptable, but a one-line mention in the request skill next toGITHUB_TOKENwould help, since the 40-character fallback needs agit rev-parsethe agent may not think of.Nits:
claim_commitsis not cleared onreleaseor expiry, so adonewith no newclaimsilently uses the old claim's commit. Dropping it on those two events (or requiring--commitwhen the claim is gone) is cleaner.Commit:orHead:are swallowed by the request parser. Harmless in practice.docs/test-requests.mdwill conflict with #2807 as you said; whoever lands second rebases.Relay: only the request message was trialled in Discord. The claim, result and
updatemessages (and an unknownupdateaction) have not been seen by the relay yet, so that check is still open before this is relied on. I would not merge until it is done. Nothing here depends on game or GPU measurements, so no in-game evidence is needed.d22aec74f8todaad135081Thanks for the careful read. All four points are right, and I am taking them as you ordered them:
currentview in the JSON output, with both skills andclaim's refusal worded in terms of it, so an agent no longer skips a card because of a result for an older commit.requestrefuses a commit outside the pull request when GitHub can tell.git rev-parsefor the full hash.The nits too: the claim's commit dropped on release and expiry, and note lines that start with
Commit:orHead:.The relay: agreed that it should not merge before the claim, result and
updatemessages have gone through the real room. I will run them on the trial card once the fixes are pushed and ask you to look at how the relay shows them. If the card cannot be claimed without the label, I will ask you for the label on this pull request for that one trial.Thanks; each point is now addressed:
56661df6: JSON exposescurrent_results; both skills and claim refusals distinguish the card's pin from a moved PR head.8652d4b8: request/update verify non-head commits with GitHub. Before building,verifychecks the fetched PR ancestry and prints the pinned diff; an outside commit releases the claim. A real Git fixture covers a fetchable outside commit.6849b187: a moved head sends no claim without explicit--commitconfirmation; unattended loops must skip it. Verification also stops if the head moves after claiming.3a8262d2: the request skill putsgit rev-parse --verify "HEAD^{commit}"beside the token/outage instructions.Nits:
8db228eeclears commit/head snapshots when claims end;daad1350preserves metadata-looking note lines and documents the reserved trailing footer.Rebased cleanly onto
4cf785a0; headdaad1350. No conflicts; all seven patches unchanged in the final rebase.Checks: 270 offline checks pass, including the real old client. The whole Linux suite: 501 passed, 1 failed, 20 skipped; only main's known
test_readme_menu_rows.pyfailure (missing “Skip opening”). Pre-push check: PASS.A full run of the project's checks on this exact head in my fork, Windows included:
tests/test_test_requests.pypasses on Ubuntu and Windows. Red there were only tests this branch does not touch: main's two known ones (test_readme_menu_rows.py, and on Windowstest_wb_shadow_remake.py, fix in #2868), plus one Windows failure oftest_recorder_sync.pywhose own output shows a timing-dependent negative case ("vkDestroyBuffer made without waiting ... NOT CAUGHT"); I will look at that one separately.The live claim/update/result trial is still pending. Could you add
testing wantedto #2830 for T-6BH3? I will update its old pin to the reviewed head first, then capture each relay step; no game run or unrelated PR is needed.