Skip to content

feat(queen): MY RUNNERS cabinet on the leaderboard tab - #1205

Merged
dmitrii-f-t27 merged 1 commit into
mainfrom
claude/gallant-bardeen-h2hgaa
Oct 1, 2026
Merged

dmitrii-f-t27 merged 1 commit into
mainfrom
claude/gallant-bardeen-h2hgaa

Conversation

@dmitrii-f-t27

Copy link
Copy Markdown
Collaborator

Description

The LEADERBOARD tab says "Lend the swarm a key and watch your bees work" but offered no way to do it. This PR adds a MY RUNNERS cabinet to that tab. A person signed in on app.t27.ai can create, list and revoke runner tokens.

A runner is a lane that runs on the lender's own machine, under the lender's own provider account. The key never moves, which is the design how-to-join-the-swarm recommends because OpenAI, Anthropic and Google forbid handing a key to third parties. This page has no field for a provider key and never sees one.

The server side is gHashTag/BrowserOS#518 (/queen/me/runners, /queen/runner/heartbeat). It must be deployed first. Until then the panel shows "The Queen did not answer".

{
  "version": 1,
  "head_sha": "e7cc424ae7c7b76d382273805b9f044d8eaab9c8",
  "summary": "The LEADERBOARD tab invited people to lend the swarm a key but had no way to do it. It now has a MY RUNNERS cabinet. A signed-in person on app.t27.ai creates, lists and revokes runner tokens for runners that use their own provider key on their own machine. The page never takes a key.",
  "changes": [
    "apps/website/src/lib/queenRunners.ts: pure cabinet logic with an injected fetch. The session token is sent only as a bearer, with credentials omitted and exactly two headers. A runner token is accepted only in the qr_ format the Queen issues, and is shown once.",
    "apps/website/src/components/QueenRunners.tsx and QueenRunners.css: the panel, with EN/RU copy, a one-time token display with setup lines, a revoke confirmation, and a pointer to app.t27.ai/queen when it is opened on t27.ai (bridge path).",
    "apps/website/src/components/QueenLeaderboard.tsx: renders the panel. Rows are keyed by lane kind plus first lane, so a runner whose Telegram name equals an operator lane name does not duplicate a React key.",
    "apps/website/qa/queen-runners-contract.mjs, package.json and .github/workflows/website-checks.yml: a new check:queen-runners contract wired into CI.",
    "apps/website/qa/queen-contrast-contract.mjs: registers the new stylesheet. The panel's inner grounds are opaque."
  ],
  "tests": [
    {
      "command": "cd apps/website && npm run check:queen-runners",
      "status": "passed",
      "result": "queen-runners contract: ok",
      "evidence": "Local run on head e7cc424 in the authoring session"
    },
    {
      "command": "cd apps/website && node --experimental-strip-types qa/queen-contrast-contract.mjs && npm run check:queen-fallback-parity",
      "status": "passed",
      "result": "Contrast: 24 pairs, worst 5.39:1. Fallback parity: PASS 218/218. Both initially failed on the new sheet and were fixed by registering it and making its grounds opaque.",
      "evidence": "Local run in the authoring session"
    },
    {
      "command": "cd apps/website && npx vite build && npm run typecheck:ratchet && npx eslint src/components/QueenRunners.tsx src/lib/queenRunners.ts qa/queen-runners-contract.mjs",
      "status": "passed",
      "result": "Build succeeded. Ratchet: 179 errors across 26 files, the same as the baseline, and no file gained errors. ESLint clean on the new files. QueenLeaderboard.tsx keeps its existing react-refresh/only-export-components error, which is unchanged from main.",
      "evidence": "Local run in the authoring session"
    },
    {
      "command": "Every npm run check:* step listed in .github/workflows/website-checks.yml, except build, lint, typecheck, render, deployed and mobile audit",
      "status": "passed",
      "result": "All passed locally after the fixes above.",
      "evidence": "Local run in the authoring session"
    },
    {
      "command": "Manual check of the panel in a browser on https://app.t27.ai/queen/",
      "status": "not_run",
      "result": "The panel reads the session only on the app.t27.ai origin, and the server routes are not deployed yet, so it was not viewed live.",
      "evidence": "Not run: requires the app.t27.ai origin and a deployed server"
    }
  ],
  "limitations": [
    "Runners can register and show as online, but cannot take tasks yet. Claim/complete, review of a branch pushed from outside the container, and a runner CLI are the next stage.",
    "Depends on gHashTag/BrowserOS#518 being deployed to trios-agent-server. Until then the panel reports that the Queen did not answer.",
    "To verify the person, the cabinet sends the app's full session token to the Queen, which forwards it only to vibee-render whoami. A narrower token is a possible follow-up."
  ],
  "tags": ["Engineering", "Security", "Queen"],
  "blog": {
    "title": "Lending a lane without lending a key",
    "summary": "The swarm's leaderboard now has a cabinet that issues runner tokens for runners that use the lender's own key on the lender's own machine, rather than a form that collects provider keys.",
    "outline": [
      "The leaderboard invited people to lend a key, but most providers' terms forbid handing a key to a third party.",
      "The cabinet issues a runner token instead. It is shown once, stored only as a hash, cannot spend quota, and lets the person's own runner be credited on the leaderboard.",
      "Not done yet: handing tasks to runners and reviewing their branches, which is the next stage."
    ]
  }
}

Related Issue

None filed. Server counterpart: gHashTag/BrowserOS#518.

Specification Link

Not applicable. This is a hand-written React/TypeScript change in apps/website, like the rest of that app.

Changes Made

  • Feature: Added a MY RUNNERS cabinet to the LEADERBOARD tab (create, list and revoke runner tokens).
  • Bug Fix: Leaderboard rows are no longer keyed by display name alone.
  • Tests: Added the qa/queen-runners-contract.mjs contract and wired it into CI.

Files Changed

  • apps/website/src/lib/queenRunners.ts - cabinet logic (pure, injected fetch)
  • apps/website/src/components/QueenRunners.tsx, QueenRunners.css - the panel
  • apps/website/src/components/QueenLeaderboard.tsx - renders the panel; row key fix
  • apps/website/qa/queen-runners-contract.mjs - new contract
  • apps/website/qa/queen-contrast-contract.mjs - registers the new sheet
  • apps/website/package.json, .github/workflows/website-checks.yml - check:queen-runners

Golden Chain Checklist

  • Spec First / Code Generation: Not applicable. apps/website is hand-written TSX, like its neighbours.
  • No Forbidden Files: This PR adds .tsx, .ts and .css files in apps/website, where all existing UI lives.

Testing Checklist

  • Build: npx vite build passes
  • Unit/contract tests: check:queen-runners, contrast and fallback-parity contracts, and the other website-checks steps pass locally
  • Manual Testing: Not done in a live browser (see limitations)

Test Results

queen-runners contract: ok
queen-contrast: 24 pairs measured over a lit and a dark field, worst 5.39:1
Queen fallback parity: PASS (218/218)
typecheck ratchet: 179 errors across 26 files; baseline 179 across 26; no file gained type errors
✓ built in 29.34s

Performance Impact

  • No performance change. One GET when the leaderboard tab opens on app.t27.ai, and none on t27.ai.

Breaking Changes

  • No - This PR is backward compatible

🔥 TOXIC VERDICT

What Works

  • Creating, listing and revoking runners works against the logic tested in the contract, with exact headers and credentials: 'omit'. A token is shown once.
  • The page has no key field. The contract asserts that neither file uses storage, cookies, a password input or apiKey.

What Doesn't Work

  • A runner cannot do work yet. The heartbeat says so honestly (work: null).
  • The panel was not viewed in a live browser.

Tech Debt

  • The full session token is forwarded to the Queen for verification. A scoped token would be better.

Known Issues

Toxic Verdict

Overall Assessment: APPROVE once the server PR is merged and deployed.

Self-Score: 7/10. The cabinet is solid, but runners can't do anything useful yet.

🌳 TECH TREE Options

Option 1: Runner claim/complete protocol

  • Description: /queen/runner/claim and /queen/runner/complete; the review reads the runner's pushed branch from GitHub.
  • Complexity: ★★★★☆

Option 2: Runner CLI

  • Description: A small CLI that heartbeats, claims and runs a bee with the user's local key.
  • Complexity: ★★★☆☆

Option 3: Scoped cabinet token

  • Description: vibee-render issues a short-lived token scoped to the runner cabinet, so the full session token is not forwarded.
  • Complexity: ★★☆☆☆

Recommendation: Option 1. Without it, runners earn nothing.

Deployment Notes

Reviewer Notes

  • Check the credential handling in src/lib/queenRunners.ts against the rules in appSessionIdentity.ts.

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings
  • I have tested this PR locally (contracts and build; not in a live browser)

🤖 Generated with Claude Code

https://claude.ai/code/session_01SJ8KjRoGNBoHBoDR92fAo2


Generated by Claude Code

The LEADERBOARD tab invited people to "lend the swarm a key" and had no
door. It now carries a cabinet where the person signed in on
app.t27.ai mints, lists and revokes runner tokens (trios-agent-server
/queen/me/runners). A runner runs on the lender's own machine with the
lender's own provider key; this page has no field for a key and never
sees one.

- lib/queenRunners.ts: pure decisions with an injected fetch; the
  session token rides only as a bearer with credentials omitted and
  exactly two headers; a runner token is accepted only in the shape the
  Queen mints and shown once.
- On t27.ai (bridge path) the panel points to app.t27.ai/queen instead
  of forwarding the read-only game token.
- Leaderboard rows are keyed by lane kind + first lane, since a runner's
  Telegram name can equal an operator's lane name.
- qa/queen-runners-contract.mjs wired into website-checks; the new sheet
  is registered with the contrast contract and uses opaque inner grounds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SJ8KjRoGNBoHBoDR92fAo2

Copy link
Copy Markdown
Collaborator Author

pr-opened is red, but the failure is not caused by this PR. The job fails at its first step, a gh api graphql lookup of the PR's project item, with gh: Bad credentials (HTTP 401) (log). That step authenticates with the token stored in the repository secrets. No test or code from this PR runs in that job.

The same job fails the same way on #1204 (job 110364307888), which was opened two hours earlier and touches unrelated files.

There is no code fix to port: the project-automation token used by that workflow needs to be rotated in the repository secrets. I have not re-run the job, because it will hit the same 401 until the token is replaced.


Generated by Claude Code

Copy link
Copy Markdown
Collaborator Author

⚡ Brain Health Check is red, but this PR did not cause it. The step runs tri stress --health, which currently prints only ⚠️ stress-test: TODO - not implemented yet and no Score: line. The workflow's own error says "brain health was NOT MEASURED … This is not a health regression" (log).

The same check fails the same way on #1204, and this PR does not touch the Zig CLI.

There is no fix to port yet: the check stays red until tri stress --health is implemented or the workflow stops treating "not measured" as a failure. I have not re-run it, because the result is the same on every run.


Generated by Claude Code

@dmitrii-f-t27
dmitrii-f-t27 merged commit da10c13 into main Oct 1, 2026
24 of 27 checks passed
@github-actions github-actions Bot added status:completed Done and removed status:in-progress 🔵 Agent working labels Oct 1, 2026
dmitrii-f-t27 pushed a commit that referenced this pull request Oct 1, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SJ8KjRoGNBoHBoDR92fAo2

# Conflicts:
#	apps/website/qa/queen-runners-contract.mjs
#	apps/website/src/components/QueenRunners.tsx
#	apps/website/src/lib/queenRunners.ts
github-actions Bot added a commit that referenced this pull request Oct 1, 2026
feat(queen): MY RUNNERS cabinet on the leaderboard tab (#1205)

The LEADERBOARD tab invited people to "lend the swarm a key" and had no
door. It now carries a cabinet where the person signed in on
app.t27.ai mints, lists and revokes runner tokens (trios-agent-server
/queen/me/runners). A runner runs on the lender's own machine with the
lender's own provider key; this page has no field for a key and never
sees one.

- lib/queenRunners.ts: pure decisions with an injected fetch; the
  session token rides only as a bearer with credentials omitted and
  exactly two headers; a runner token is accepted only in the shape the
  Queen mints and shown once.
- On t27.ai (bridge path) the panel points to app.t27.ai/queen instead
  of forwarding the read-only game token.
- Leaderboard rows are keyed by lane kind + first lane, since a runner's
  Telegram name can equal an operator's lane name.
- qa/queen-runners-contract.mjs wired into website-checks; the new sheet
  is registered with the contrast contract and uses opaque inner grounds.

Claude-Session: https://claude.ai/code/session_01SJ8KjRoGNBoHBoDR92fAo2

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants