runner next claimed the oldest pending build in the whole queue, so every
runner executed every repository's steps. Fine on the server; it rules out
running one anywhere else, because a runner meant for one project will
sooner or later claim someone else's build — and with open registration
that someone need not be known to the operator.
runner next now takes optional owner/name arguments, and the runner
takes -repos. Empty means any, so an existing runner is unaffected.
Shape
The filter goes into ClaimBuild, so the claim stays a single statement
and two runners still cannot take the same build. The control command
resolves each name through resolveRepo with CanRead, so a scope naming
a repository the runner account cannot see fails rather than silently
matching nothing.
This is scoping the runner asks for, not an ACL the server holds over it. A runner account is admin — it has to be, to claim at all — so the boundary is the operator choosing how to start it. That is the honest framing, and it is what the Admin wiki should say once this lands.
Testing
TestClaimBuildScopedToRepos— a scoped claim skips an older build in another repository, reports empty when its scope is exhausted, and an unscoped claim still takes the one it left.TestRunnerNextScopedToRepos— the same through the SSH command, which is what the runner actually calls with its repo arguments.
Full suite green.
Closes #66