feat: test farm coordinator, dashboard and desktop agent #3
No reviewers
Labels
No labels
risk
high
risk
low
risk
medium
ci: approved
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Beanstalk!3
Loadingβ¦
Reference in a new issue
No description provided.
Delete branch "HumanBean/Beanstalk:feat/test-farm"
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?
Longshot PRs need testing on hardware the core team doesn't own, and a full build and A/B run takes too long to babysit. This adds Beanstalk, the Longshot Test Farm: an approver comments
@Beanstalkon a PR, an AI model writes a test plan for that exact commit, and volunteer PCs build it next tomainin a sandbox, run both and post the numbers back.What changed
Coordinator (
coordinator/beanstalk/, Python 3.13, Starlette, Postgres)web.py: the agent API (docs/protocol.md), the HMAC-checked/webhook, and the read-only dashboard (templates/,static/).webhooks.py: PR opened, pushed, labelled, closed. A new push records the commit with its sensitive paths, cancels the old commit's jobs and makes its π requests stale. Label events the bot itself caused are ignored, so the farm's approval label can't echo back as a PR change.commands.py:@Beanstalkand/beanstalk(start, run again,<words>,plan,cancel(queued jobs; running ones finish and count),cancel forceandrevoke(running ones stop within about 5 s),help), π for approvers, and π requests from everyone else, polled since Forgejo sends no webhook for reactions. A stale request's reply is edited, not answered again.trust.py: the tiers (untrusted, reviewed, double-reviewed; no auto tier) and the sensitive paths that need two approvers.planner.py,llm.py: the AI planner. It fences the PR's text in nonce-marked data blocks, checks the answer as a plan, retries once, and falls back todefault_plan.toml.llm.pycalls OpenAI's Codex backend with a ChatGPT sign-in whose rotating tokens live in Postgres.plan.py,menu_options.py,destinations.py,default_plan.toml: plan schema 4 (targets by tags, plus VRAM and RAM sizes (vram_gb = 8,"> 12","4-8", rounded to whole GB as people say them) and GPU/CPU model patterns (gpu = "gtx 1080","gtx 10xx",cpu = "5800x3d"), build variants from an allowlist of build options (march,hot_opt,split_giants), start states, settings, switches, matrix, steps, probes, rules; a plan without variants stays schema 3 for older agents), the Insert menu's rows (generated byscripts/gen_menu_options.py) and the teleport destinations.scheduler.py: jobs per commit, round, target and slot; offers (rarest hardware first, counting tags, sizes and models; author share cap), leases, heartbeats every few seconds (next_s) so a stop arrives at once, release, a tester's skip and Run it again (unskip), the sweep. Every try is recorded injob_attempts(opened on accept, closed by the report, a fail, a stop or skip, an expired lease or a cancel).tickets.py,agents.py,reports.py: signed tickets, agent registration with a Forgejo token, report checks (report v3: what was in use per cell,mismatch; reports are plain JSON authenticated by the agent token and the lease, an old signed envelope still unwrapped) and outlier flags.reporter.py: the statuses (none until the farm is engaged on a PR), the one PR comment with a Measurements block in Longshot's PR template format and a Flags and settings table, and the label (changed only when it is wrong).migrations/0001β0009(0006 turns storedos/gputargets, jobs and agents into tags; 0007 drops the agents' report keys and addsjobs.skipped_agents; 0008 the testers' status; 0009job_attempts, filled from past reports, failures and skips),tests/,Dockerfile, hash-pinnedrequirements*.lock.Agent (
agent/, .NET 10, Avalonia 12)Core/Envelope.cs,Policy.cs,JobRunner.cs: ticket checks against the pinned coordinator key, the volunteer's policy (when to test and the disk it may use; older keys ignored), the job loop with heartbeats at the coordinator's pace, Stop (release), Skip this test and Run it again, which takes jobs only while testing is on, and only while the PC has room (CPU under 50 %, and 4 GB of memory free or a quarter of it if that is less;Core/Load.cs). It tells the coordinator its status (POST /api/v1/agents/me/status), and reports that could not be sent are kept and sent again (PendingReport.cs). The agent key is gone: an oldagent_key.pemis deleted at start.Core/AgentConfig.cs,DataFolder.cs: the setup, testing on/off and the close prompts' answers; one data folder for everything big, with its minimum (100 GB on Linux, 150 GB on Windows) and the free-space warning.Core/Workspace.cs,JobPipeline.cs: tools fetched outside the sandbox (and Longshot's ZBIC reader, which reading some.nupfiles needs), the warmmainbase and the PR's pack withscripts/dev_packs.py, both runtimes, per build variant (each variant its own cached base, keyed by commit and options). The game'sromfsis kept once and shown read-only to the base, the pack and both runtimes; lifted code is kept betweenmainbuilds and read-only for PRs; the shader caches carry over whenmainmoves. Each runtime gets its own folder, written only by its own side, and the baseline its ownbase.json, so a PR's code can't change whatmain's side runs.Core/Sandbox.cs: bubblewrap on Linux.Core/WindowsSandbox.cs,WindowsSelfTest.cs,WindowsPlan.cs,WindowsTools.cs: the AppContainer mode, thebeanstalk-runnerfallback and the self-test that chooses between them.Core/Tags.cs: the PC's tags (OS, GPU maker, Vulkan driver,igpu/dgpu, Steam Deck from DMI), the volunteer'sextra_tags, and the same size and model matching as the coordinator.Core/Plan.cs,ScenarioRunner.cs,Probes.cs,Report.cs,Hardware.cs: the same plan checks as the coordinator, the game driven through its control bridge, the probes, what was in use (each setting read back, each switch's "in use" log line, each build's CPU level) and the scrubbed report.Core/AgentUpdate.cs,App/ViewModels/UpdatesViewModel.cs: self-update in the window, as the Longshot Launcher does it: a check at start and every 6 hours, a banner on the main screen (Update Beanstalk, with progress and Cancel), and an Updates section in Settings (Automatic, Nightly, Beta, Release; Check now). While a test runs it offers "Update after this test": the runner is held so it takes no new job, the update waits for the test to end, then the agent restarts into the new version with testing still on. Development builds don't update themselves.App/: the window (sign-in, then the setup with the launcher's game picker, then the main screen: Start testing / Stop, the running test (its live page, with Skip this test), recent tests and each test's page; Settings and Log out), the tray and thebeanstalk-agentcommand line (setup --data-dir,start,stop).tests/: checks, including every plan fixture read by both sides.scripts/: packaging and releases.Deployment:
deploy/compose.example.yml,deploy/openai-login.sh.CI:
.forgejo/workflows/ci.yml(PR title; coordinator tests and agent checks onmain),release-agent.yml: the agent's channels, nightly (each merge tomainthat changes the agent), beta (avX.Y.Z-beta.Ntag, the firstv0.1.0-beta.1) and release (avX.Y.Ztag, the firstv0.1.0), signed with Beanstalk's own release key.Docs:
README.md(the front door),docs/using.md(new: for BigBeans and PR authors),docs/architecture.md(new),docs/test-plan.md,docs/protocol.md,docs/report-schema.md,docs/deploy.md,agent/README.md,CONTRIBUTING.md,AGENTS.md. The wiki Spec is updated to match.How to review
A suggested reading order, from the overview to the riskiest parts:
docs/architecture.md, thendocs/using.mdfor what users see.coordinator/beanstalk/trust.py,commands.py,webhooks.py. Check that nothing runs without an approver's approval of the exact head, and that sensitive paths need two.docs/protocol.md,coordinator/beanstalk/tickets.py,scheduler.py(accept,heartbeat,release),agent/Core/Envelope.cs,coordinator/beanstalk/reports.py(plain reports, the transition for old envelopes).agent/Core/Sandbox.cs,Workspace.cs(what runs outside it), thenWindowsSandbox.csandWindowsSelfTest.cs.coordinator/beanstalk/planner.py(fencing, checks, fallback),llm.py, andplan.pywithdocs/test-plan.md.Testing
Tested
tags = []is any PC;radv,linux+amd,steamdeck). Tag matching, names, the validator's refusals (including oldos/gputargets), reservedextra_tags, the scheduler's order, migration 0006 and Steam Deck detection from made-up DMI files are covered by those tests. Deployed (v11 onward; migration 0006 ran on the live database); no real job has used one yet.mainbase build in bwrap; the PR's pack and both runtimes; the game booting in the sandbox with the control bridge, recording frame times and VRAM.--die-with-parentkilled builds when a .NET thread-pool thread retired. Processes now start from one long-lived thread.~/.cache/beanstalk-sock/<random>, never/run/user.protocol.file.allowblocked the job's local clone. It is allowed for that one clone only.Not tested
romfs, the kept caches), and on Windows at all.mismatchon a real game and build: only made-up logs and fake bridges so far. Switch "in use" detection relies on Longshot naming each switch in its own log line; a switch that logs nothing is recorded asnot_logged, not a mismatch.start = "new"), live setting changes (option_setand read-back), load-time polling, theRX_VK_PASS_TIMINGand shader-preparation parsers on real logs.start = "save:<name>") on a real job (Longshot #543 and the first save, #610, are merged).Needs other testers
min_reportsand outlier flags.Deployment
Live at https://beanstalk.magicbean.dev on the Unraid magicbean stack:
magicbean-beanstalk(the coordinator, image v21) andmagicbean-beanstalk-db(Postgres 18), behind the Cloudflare tunnel. The Longshot webhook goes to the public/webhook, checked with HMAC. The bot account is@Beanstalk(team FarmBot with write on Longshot, and in BigBeans to read its members). Approvers are BigBeans only (FARM_MAINTAINER_TEAMS=BigBeans), and BigBeans may start their own PRs (FARM_SELF_APPROVE_TEAMS=BigBeans). The planner usesgpt-6.1-terraat medium effort through a ChatGPT sign-in made bydeploy/openai-login.sh.docs/deploy.mdhas every step.Follow-ups
main, and testers moving from the dev builds to the nightly (dev builds don't update themselves).--fsrpass-through inscripts/dev_packs.pywould let FSR 4 become a build variant (left out for now).v0.1.0-beta.1) and release (v0.1.0).c5b50b8463361bb491f9Pushed: the bot account is now
@Beanstalk, and a mention works as the trigger (@Beanstalk,@Beanstalk <what to test, in words>,@Beanstalk canceland so on; quoted lines and code blocks are ignored). The farm reacts π to every comment it takes as a command, before planning. Repo saves copy onlyslot_00, neveraccount.savoroption.sav. 276 coordinator tests pass, plus 611 agent checks. Live on the coordinator as v6.361bb491f988178d71db88178d71db49caafa2edPushed (live as v8):
BigBeansteam only (FARM_MAINTAINER_TEAMS), and BigBeans may start the farm on their own PRs (FARM_SELF_APPROVE_TEAMS).@Beanstalk: the farm replies, and an approver approves with π on the request. Reactions are polled every 30 s, since Forgejo sends no webhook for them. The π is refused if the PR changed since the request, and requests expire after 7 days.runis folded into the trigger:@Beanstalkon a finished or cancelled commit runs it again with the same plan.targetsis removed.49caafa2ed61165d5bea61165d5beaffdc1044d5ffdc1044d505221145000522114500591998faf8591998faf80278608bb20278608bb2dce17f50dedce17f50de9bffbefd079bffbefd0797d91374c5Test builds of the agent (
dev-ee5fd24), updated 2026-11-15. They are not signed and not a release.beanstalk-agent-dev-ee5fd24-windows-x64-setup.exe, a single self-contained file; no .NET install is needed. It is unsigned, so SmartScreen will warn: choose More info βΊ Run anyway.beanstalk-agent-dev-ee5fd24-x86_64.AppImage. Runchmod +xon it, then run it.They are built from this branch plus local changes that are not pushed here yet:
SHA-256 of the files inside the zips:
97d91374c53f841c9cd13f841c9cd12fe5b865272fe5b86527fa856b7233WIP: feat: test farm coordinator, dashboard and desktop agentto feat: test farm coordinator, dashboard and desktop agent