@volter/twin-runhuman
v0.1.35
Published
Local Runhuman 1 (runhuman.com/api) twin: job create/read/list, the tester claim-to-completion lifecycle, RH1-exact refusals. Built on @volter/world-core.
Readme
@volter/twin-runhuman
Local twin of Runhuman 1 (RH1, runhuman.com/api), the human-QA marketplace: a customer posts a
job, a tester claims it, tests, submits, and the job completes with a cost. Built on the shared
@volter/world-core kernel; every write is an action in the kernel log.
The vendor is our own product, so RH1's source is the specification: volter-ai/runhuman,
read at 2f2fcb2c5 (packages/api/src/routes/jobs/**, routes/projects.routes.ts,
middleware/*auth*.ts, packages/shared/src/contracts/{job,tester-job}.schema.ts). The file header
of src/runhuman-twin.ts maps every route to its RH1 source file.
bun packages/twin/runhuman/src/cli.ts serve --port 47311 --root <world-dir>A world points RH1 clients at the twin through RUNHUMAN_API_URL (the RH1 CLI's base-URL
override). RH2 reads its human-marketplace provider's spec.url instead; set it to the same URL.
Seeding a world
RH1 creates organizations, projects, API keys and tester profiles outside the job API (dashboard, Clerk webhooks, admin approval). The twin seeds them through twin-only routes a real client never calls:
curl -X POST $URL/_twin/organizations -d '{"id":"org-1","name":"Acme"}'
curl -X POST $URL/_twin/projects -d '{"id":"proj-1","organizationId":"org-1","name":"Web"}'
curl -X POST $URL/_twin/api-keys -d '{"organizationId":"org-1","key":"rh_…"}' # key minted when omitted
curl -X POST $URL/_twin/testers -d '{"email":"[email protected]","alias":"tess"}' # → "Bearer [email protected]"
curl -X POST $URL/_twin/settings -d '{"jwtSecret":"…"}' # testerToken signing secret; minted from entropy when never seededA seed makes a subject and never replaces one: an organization, project or API key whose id (or key) is already held
answers 409 {error}.
Web users (the tester side) authenticate in RH1's Clerk mock-mode form Bearer clerk_<email>.
Coverage
src/runhuman-capabilities.ts enumerates RH1's surface at 2f2fcb2c5: the public REST reference
(packages/static-site/src/content/docs/api.mdx), the jobs router, the customer-API allowlist and
the project job list. 92 capabilities: 16 done, 76 todo. Every done has a verify() that
drives the twin on a fresh root and checks RH1's statuses, bodies and refusals.
Modelled, with RH1's exact shapes, statuses and refusal bodies:
POST /api/jobs— body validation (RH1's zod schema, FastifyFST_ERR_VALIDATIONenvelope), API-key / web-user auth, project resolution and access, URL and session-limit checks, the external-capture desktop rule, the per-org active-job cap (12),201 {jobId, message}.GET /api/jobs/:jobId(enriched + result-gated) andGET /api/jobs/:jobId/status.GET /api/projects/:projectId/jobs(limit/offset pagination, customer list columns).- The tester lifecycle:
POST /api/jobs/:jobId/claim(claim gate, pool requirements, surface rules, HS256 testerToken),GET|PATCH /api/tester/jobs/:jobId,POST …/process-results,GET …/processing/:processingJobId,POST …/issue-review(continue),POST …/end(release / cancel / platform issue), completion with RH1's cost ($0.0085/sover the tester window, capped at the allotted time).
Where RH1 runs a worker or a model:
- Results pipeline. RH1 queues an AI run on BullMQ. The twin runs it when the status is
first polled: extract keeps the tester's submitted
resultand extracts no issues or feedback; finalize setspassStatusfromresult.data.success(true →pass, false →fail, otherwisenot_applicable). - Timers. The release throttle (
pending → queued → waiting), claim-window expiry, no-response timeout andoverduerun on timers in RH1. The twin runs none, so a job stayspendinguntil claimed. - Billing. Funds are never reserved at creation. RH1's billing queue settles a completed
job's charge and records
billedAt,billedAmountCentsandbillingIdempotencyKeyon the job. The twin runs no queue, so the charge settles when the job completes. - Instruction validation (an LLM) and the URL safety check accept every input.
Not modelled. These answer RH1's JSON 404 {"error":"Not found"} with an x-twin-gap header,
never a fabricated success: templates, PR/issue test plans, KB enhancement, GitHub repos,
outputSchema, attachments, sideload/social-video tiers, issue-tracker integrations,
issue-review reprocess, and every other RH1 route (job list, rerun, share, artifacts, …).
No UI mirror
RH1's customers post jobs from code (the CLI, the GitHub Action, RH2's marketplace performer). The tester web app is RH1's own worker product. Its core loop is the tester API this twin serves, so there is no dashboard mirror.
