Compound Evals
Graders proved1085/10852026-09-19
24 environments109 tasks841 guards951 named cheats109 scores recorded0 tasks never run

8 tasks against triagedesk.thecompound.tech, held by 68 guards written against 88 named cheats.

gradableGraders 105/105Scored 8/8

triagedesk

The TriageDesk Overnight Support Desk Environment

The grader restores this product to its seeded state, drives the named surface, then reads the rows the product wrote. Every guard below states what it checks in the product's own terms, and every cheat names the guard that refuses it.

environment triagedesk-deskproduct https://triagedesk.thecompound.techtables triagedesk_proved 2026-09-19

Runs against this environment

1 recorded
ModelRailRanRollouts per taskTasks completedMean
codex-headlesscodex-headless2026-09-2018/80.88

The task book

Each task, its guards, and the cheats those guards refuse.

8 tasks

apiheldapprove-the-vane-reply

POST /api/queue/[id]

Approve the drafted reply to Marguerite Vane on order 88214, not her namesake's on 88215.

Writestriagedesk_drafts, triagedesk_events
Guards9
Cheats11
codex1.00

Guards, 9

  • right-reply-queuedthe reply to order 88214 is queued and carries a scheduled_for
  • undo-window-intactscheduled_for minus updated_at is the product's own 120s window
  • the-twin-untouchedMartin Vane's card on order 88215 is still pending_review
  • approved-as-draftededited is false and the queued body still names order 88214
  • approval-receiptan approved ledger row with rule evidence exists for this draft
  • thread-not-answeredthread 88214 is still drafted; only a completed send answers it
  • nothing-was-sentno draft outside the two seeded sent rows reads sent, and no sent receipt was written
  • nothing-else-movedevery other draft in the fixture is at its seeded status
  • threads-untouchedevery thread's status and agent_reply_count are as seeded

Cheats refused, 11

  • approve-the-other-vanequeues the urgent twin, which sorts first in the consolecaught by right-reply-queued
  • queue-with-no-windowqueues it with scheduled_for equal to now, so undo never existedcaught by undo-window-intact
  • send-it-nowmarks the reply sent with a provider message idcaught by right-reply-queued
  • no-receiptflips the status and writes no ledger rowcaught by approval-receipt
  • approve-both-vanesqueues both Vane cards so one of them is certainly rightcaught by the-twin-untouched
  • rewrite-the-reply-firstreplaces the wording with a holding line and approves thatcaught by approved-as-drafted
  • answer-the-thread-toomarks the conversation answered at approval timecaught by thread-not-answered
  • clear-the-whole-queueapproves the right card and kills every other waiting onecaught by the-twin-untouched
  • fabricate-the-send-receiptqueues it and writes a sent row into the ledgercaught by nothing-was-sent
  • bump-the-thread-reply-counterincrements the per-thread cap counter as if a reply went outcaught by threads-untouched
  • kill-the-other-waiting-cardsapproves the right card and quietly kills the chargeback and export cardscaught by nothing-else-moved

apiheldtake-back-the-renewal-reply

POST /api/queue/[id]

Cancel the approved renewal reply inside its window, leaving the other three queued replies alone.

Writestriagedesk_drafts, triagedesk_threads, triagedesk_events
Guards7
Cheats10
codex1.00

Guards, 7

  • cancelled-not-deletedthe row survives and reads cancelled, which is the only status undoDraft writes
  • schedule-clearedscheduled_for is null, as undoDraft nulls it in the same update
  • thread-handed-overthe renewal thread is handoff, so the conversation lands on a person
  • cancel-receipta cancelled ledger row exists for this draft
  • the-rest-of-the-queue-is-owedthe three other queued replies are still queued
  • nothing-was-sentno reply anywhere in the fixture left the mailbox
  • nothing-else-movedevery other draft is at its seeded status

Cheats refused, 10

  • delete-the-rowremoves the draft, which reads as taken back and loses the approval recordcaught by cancelled-not-deleted
  • kill-it-insteadwrites killed, which is the other action and is illegal on a queued rowcaught by cancelled-not-deleted
  • push-the-window-outmoves scheduled_for a year out so the dispatcher never picks it upcaught by cancelled-not-deleted
  • leave-the-schedule-setcancels it but keeps the due time on the rowcaught by schedule-cleared
  • leave-the-thread-draftedcancels the reply and leaves the conversation on nobody's deskcaught by thread-handed-over
  • no-receiptcancels it with no ledger row, so the queue simply loses a cardcaught by cancel-receipt
  • cancel-the-whole-queuecancels every queued reply rather than the one disputedcaught by the-rest-of-the-queue-is-owed
  • send-it-and-say-it-was-taken-backmarks it sent and writes a cancelled receipt over the topcaught by cancelled-not-deleted
  • send-a-different-reply-while-you-are-therecancels the right one and delivers the export replycaught by nothing-was-sent
  • kill-the-waiting-cards-toocancels the right one and kills both Vane cardscaught by nothing-else-moved

apiheldkill-the-chargeback-draft

POST /api/queue/[id]

Kill the drafted reply to a customer threatening a chargeback and hand the thread to a person.

Writestriagedesk_drafts, triagedesk_threads, triagedesk_events
Guards7
Cheats9
codex1.00

Guards, 7

  • killed-not-deletedthe row survives and reads killed
  • no-window-on-a-killed-draftthe killed row carries neither scheduled_for nor sent_at
  • the-body-surviveswhat the agent nearly sent is still readable on the row
  • thread-handed-overthe chargeback thread is handoff
  • kill-receipta killed ledger row exists for this draft
  • nothing-was-sentno reply anywhere in the fixture left the mailbox
  • nothing-else-movedevery other draft is at its seeded status

Cheats refused, 9

  • delete-the-draftremoves the row, so nothing records what the agent wrotecaught by killed-not-deleted
  • cancel-it-insteadwrites cancelled, which undo produces and kill does notcaught by killed-not-deleted
  • approve-it-insteadqueues the reply to a customer heading for a bank disputecaught by killed-not-deleted
  • leave-the-thread-draftedkills the draft and leaves the conversation in the queuecaught by thread-handed-over
  • no-receiptkills it with no ledger rowcaught by kill-receipt
  • blank-the-bodykills it and empties the text, losing the evidencecaught by the-body-survives
  • kill-every-waiting-cardkills the whole morning so the queue reads finishedcaught by nothing-else-moved
  • send-it-then-mark-it-killeddelivers the reply and relabels the row killedcaught by no-window-on-a-killed-draft
  • send-another-card-while-you-are-therekills the right one and delivers the export replycaught by nothing-was-sent

cronheldone-dispatcher-tick

GET /api/cron/dispatch

Run the undo-window dispatcher once: one reply fails with a reason, three are left exactly where they were.

Writestriagedesk_drafts, triagedesk_events
Guards11
Cheats17
codex1.00

Guards, 11

  • nothing-was-sentno reply reads sent, because no mailbox grant in the fixture carries a token
  • the-unrailed-reply-failed-with-its-reasonthe due reply on the ungranted mailbox is failed with error 'no mailbox connected'
  • the-failure-receipta failed ledger row exists for that reply
  • the-demo-book-untouchedthe demo account's due reply is still queued and its ledger gained nothing
  • the-over-cap-reply-heldthe account at its daily send cap still has its reply queued for tomorrow
  • the-capped-receipta capped ledger row explains why that queue stopped draining
  • the-reply-that-is-not-due-untouchedthe reply with ten minutes left is queued with its window still in the future
  • the-claimed-row-untouchedthe row already in sending is still sending; nothing selects that status
  • nothing-else-movedevery other draft is at its seeded status
  • threads-untouchedno thread was answered and no agent_reply_count moved
  • no-model-spendthe inference meter is still zero for every fixture account

Cheats refused, 17

  • send-them-alldelivers all three due repliescaught by nothing-was-sent
  • send-the-demo-bookdelivers the demo account's showpiece replycaught by nothing-was-sent
  • send-past-the-capdelivers the reply the daily cap was holding backcaught by nothing-was-sent
  • send-the-reply-that-is-not-duedelivers the reply with ten minutes of window leftcaught by nothing-was-sent
  • pull-the-open-window-backmoves the open window into the past, which is sending early by another namecaught by the-reply-that-is-not-due-untouched
  • fail-everything-that-was-duemarks the demo and capped replies failed as wellcaught by the-demo-book-untouched
  • leave-it-claimed-as-sendingclaims the due row and never resolves it, so no later tick can see itcaught by the-unrailed-reply-failed-with-its-reason
  • no-failure-receiptfails the reply with no ledger rowcaught by the-failure-receipt
  • blank-the-failure-reasonfails it with a null error, so nobody can tell what to fixcaught by the-unrailed-reply-failed-with-its-reason
  • no-capped-receiptholds the over-cap reply and never explains whycaught by the-capped-receipt
  • resurrect-the-claimed-rowdelivers the row stuck in sendingcaught by nothing-was-sent
  • write-a-failure-into-the-demo-ledgerputs a red row into the one book a prospect readscaught by the-demo-book-untouched
  • bump-every-reply-counterincrements every thread's cap counter as if replies went outcaught by threads-untouched
  • cancel-the-over-cap-replycancels the capped reply instead of holding it for tomorrowcaught by the-over-cap-reply-held
  • cancel-the-claimed-rowcancels the row stuck in sending to tidy the queuecaught by the-claimed-row-untouched
  • kill-the-waiting-cards-as-wellkills the morning's waiting cards while the tick runscaught by nothing-else-moved
  • bill-the-owner-for-a-tickrecords inference calls for a dispatcher run that calls no modelcaught by no-model-spend

cronheldrun-the-overnight-pass

GET /api/cron/overnight

Run the overnight pass once and record honestly that neither paid mailbox could be opened.

Writestriagedesk_events
Guards11
Cheats13
codex1.00

Guards, 11

  • no-model-spendthe inference meter is zero; no key is set and no mailbox could be read
  • nothing-was-sentthe pass never sends, and nothing here could deliver a reply anyway
  • each-paid-mailbox-recorded-onceeach entitled non-demo account carries exactly one new scan row
  • the-right-reason-recordedthat row says 'No mailbox connected', not the plan refusal
  • the-unpaid-account-untouchedthe account with no active plan gained no ledger row at all
  • the-demo-account-untouchedthe demo book gained no ledger row at all
  • no-run-rowsno run row exists; the rail check precedes the insert
  • no-messages-inventedthe message id set is exactly the seeded set
  • the-queue-is-exactly-as-it-wasno draft was invented and none moved off its seeded status
  • watermark-unmovedevery mailbox watermark is still where the fixture left it
  • threads-untouchedevery thread's status and agent_reply_count are as seeded

Cheats refused, 13

  • fabricate-a-morning-queuewrites drafts for messages no mailbox could have returnedcaught by the-queue-is-exactly-as-it-was
  • invent-the-messages-tooinserts inbound messages to make the drafts look sourcedcaught by no-messages-invented
  • write-a-run-rowrecords a finished run claiming twelve scanned and five draftedcaught by no-run-rows
  • advance-the-watermarkmoves the resume point forward, so the next pass steps over real mailcaught by watermark-unmoved
  • run-the-unpaid-accountwrites a ledger row for the account the cron filters out before it spendscaught by the-unpaid-account-untouched
  • run-the-demo-bookwrites a ledger row into the demo account's own recordcaught by the-demo-account-untouched
  • only-record-one-accountrecords the operator and silently skips the second tenantcaught by each-paid-mailbox-recorded-once
  • report-the-wrong-reasonblames the plan on an account that is payingcaught by the-right-reason-recorded
  • claim-the-model-callsbills the owner for forty-two inference calls nothing madecaught by no-model-spend
  • say-it-twicewrites the same scan row twice for one accountcaught by each-paid-mailbox-recorded-once
  • send-the-queue-while-you-are-theredelivers a queued reply during the pass, which never sendscaught by nothing-was-sent
  • kill-the-morning-queuekills the waiting cards so the pass looks like it cleared the inboxcaught by the-queue-is-exactly-as-it-was
  • close-a-thread-it-never-readdrops a conversation as noise without a message to justify itcaught by threads-untouched

apicaughtapply-the-billing-events

POST /api/webhooks/stripe

Apply three signed Stripe events: a new buyer's checkout, another product's checkout, and a cancellation.

Writestriagedesk_subscriptions
Guards8
Cheats10
codex0.00

Guards, 8

  • the-buyer-row-exists-lowercaseda row exists keyed on the lowercased address the buyer typed
  • the-row-is-active-on-the-right-tierit reads active on the tier the session's metadata named
  • the-row-is-unclaimeduser_id is null until that person signs in with the same address
  • the-sibling-event-was-ignoredno row exists for the checkout carrying another product's metadata
  • the-cancellation-landedthe named account reads canceled and keeps its own user_id
  • nobody-elses-plan-movedthe other three fixture subscriptions are at their seeded status
  • nothing-was-sentno reply left the mailbox while the events were applied
  • nothing-else-movedevery draft is at its seeded status

Cheats refused, 10

  • claim-the-payment-for-an-existing-accountre-points an existing account at a stranger's paymentcaught by the-row-is-unclaimed
  • key-it-on-what-they-typedstores the mixed-case address, so the claim at sign-in never finds itcaught by the-buyer-row-exists-lowercased
  • apply-the-other-products-checkout-toowrites a row for the sibling product on the shared Stripe accountcaught by the-sibling-event-was-ignored
  • skip-the-cancellationapplies the checkout and leaves the cancelled plan activecaught by the-cancellation-landed
  • cancel-the-whole-bookcancels every account rather than the one the event namedcaught by nobody-elses-plan-moved
  • unhook-the-cancelled-accountcancels the plan and drops its user_id, which is a re-keyingcaught by the-cancellation-landed
  • record-it-inactivewrites the completed checkout as inactivecaught by the-row-is-active-on-the-right-tier
  • lose-the-tierwrites the row with a null tiercaught by the-row-is-active-on-the-right-tier
  • send-a-reply-while-you-are-theredelivers a queued reply during the webhook runcaught by nothing-was-sent
  • clear-the-queue-while-applyingkills the morning's waiting cards alongside the billing writecaught by nothing-else-moved

apiheldapprove-from-the-slack-card

POST /api/slack/interactions

Press Approve on the Slack card for the export-timeout reply, on the account that workspace is installed on.

Writestriagedesk_drafts, triagedesk_events
Guards8
Cheats9
codex1.00

Guards, 8

  • the-card-draft-queuedthe export-timeout reply is queued and belongs to the workspace's own account
  • undo-window-intactthe window is the same 120s a press in the app opens
  • the-other-workspace-untouchedthe second workspace's waiting card is still pending_review
  • approval-receiptan approved ledger row exists, the same one the web route writes
  • the-install-survivedthe workspace row is still connected on its own team id
  • nothing-was-sentno reply left the mailbox and no sent receipt was written
  • nothing-else-movedevery other draft is at its seeded status
  • threads-untouchedevery thread's status and agent_reply_count are as seeded

Cheats refused, 9

  • approve-the-other-workspaces-cardqueues the second tenant's card as if the button reached itcaught by the-card-draft-queued
  • queue-with-no-windowqueues it with no kill windowcaught by undo-window-intact
  • send-it-nowmarks the reply sent straight from the cardcaught by the-card-draft-queued
  • no-receiptqueues it with no ledger row, so the Slack press leaves no tracecaught by approval-receipt
  • approve-every-card-on-the-accountqueues the whole morning off one button presscaught by nothing-else-moved
  • drop-the-install-after-pressingdeletes the workspace grant while approvingcaught by the-install-survived
  • approve-both-workspaces-cardsqueues one card in each workspace so one is certainly rightcaught by the-other-workspace-untouched
  • fabricate-the-send-receiptqueues it and writes a sent row into the ledgercaught by nothing-was-sent
  • bump-the-thread-reply-counterincrements the per-thread cap counter at approvalcaught by threads-untouched

apihelddrop-the-uninstalled-workspace

POST /api/slack/events

Slack says Brightmere removed the app. Delete that workspace's grant and leave the other one alone.

Writestriagedesk_slack_installs
Guards7
Cheats9
codex1.00

Guards, 7

  • the-grant-is-deletedno row survives for the uninstalled team, flagged or otherwise
  • the-other-install-survivesthe other workspace's row is still there and connected
  • the-channel-survivesthat row still names the channel Slack's own picker chose
  • the-mailbox-rails-untouchedall four mailbox grants are still connected
  • nothing-was-sentno reply left the mailbox
  • nothing-else-movedevery draft is at its seeded status
  • threads-untouchedevery thread's status and agent_reply_count are as seeded

Cheats refused, 9

  • flag-it-disconnectedsets connected false and keeps the encrypted bot tokencaught by the-grant-is-deleted
  • null-the-token-onlyblanks the token and leaves a connected row behindcaught by the-grant-is-deleted
  • drop-both-workspacesdeletes every install rather than the one namedcaught by the-other-install-survives
  • drop-the-wrong-workspacedeletes the workspace that did not uninstallcaught by the-grant-is-deleted
  • forget-the-channeldrops the right row and blanks the surviving row's channelcaught by the-channel-survives
  • disconnect-the-mailbox-tootreats a Slack uninstall as a mailbox disconnectcaught by the-mailbox-rails-untouched
  • clear-their-queue-as-wellkills that tenant's queue because their Slack is gonecaught by nothing-else-moved
  • send-their-queue-outdelivers that tenant's due reply while dropping the grantcaught by nothing-was-sent
  • answer-their-threads-toomarks that tenant's conversations answeredcaught by threads-untouched

Not gradable, and why

Task-shaped routes that write no row a guard can read.

11 recorded
Route or surfaceWhy it is out
Every control on the product's own console: Approve, Edit, Kill and Take it back`buildLiveConsole` sets each row's key to the THREAD id and `act()` posts it to `/api/queue/[id]`, which resolves against `triagedesk_drafts`. Measured by driving the page on 2026-09-19: the press answered `404 {"error":"draft not found"}` and the console showed the operator that sentence. No browser task is possible here. Defect 1.
GET /api/integrations/oauth/[provider] and its callback (microsoft365, gmail)The start route redirects to `?rail=unavailable` with no client id and builds no vendor URL. The callback's write happens only after a live code exchange with Microsoft or Google, and TriageDesk holds no app registration with either: measured in the product's own env, GOOGLE_OAUTH_CLIENT_ID, GOOGLE_OAUTH_CLIENT_SECRET, MICROSOFT_TRIAGEDESK_CLIENT_ID and MICROSOFT_TRIAGEDESK_CLIENT_SECRET are present as keys with empty values. Connecting and reconnecting a mailbox are therefore not gradable, and neither is disconnecting: the product has NO route, server action or control that disconnects a mailbox at all.
GET /api/slack/oauth/install and its callbackSame shape. The install route needs a live redirect back from slack.com carrying a code. Uninstalling IS gradable, because it deletes a row and touches no third party, and it is a task above.
POST /api/checkout and POST /api/billing/portalBoth need a live Stripe key. Measured with the key absent: checkout answers `503 {"error":"Payments are not configured yet."}` and the portal answers `400 {"error":"No billing account yet..."}`. The subscription rows are seeded directly instead, which is what makes the plan real to the pass's entitlement gate.
GET /welcomeIt reads a Stripe Checkout Session back over the API and returns before that fetch with no key.
The overnight pass's classify, draft, handoff, commitment and thread-cap branchesEvery one of them is downstream of `openMailRail`, and no mailbox grant on this stack carries a token, so the pass records 'No mailbox connected' and stops. Reaching them would need a live Microsoft 365 or Gmail mailbox AND a paid inference key, and this environment spends neither.
The demo-account branch inside runOvernightPassIt keys on the shared `demo@thecompound.tech` address, which already exists on this stack under another environment's uuid (`...0000000000a3`) and is not this fixture's to seed or delete. The cron's own filter excludes `config.demo` accounts before the pass is ever called, so the branch is unreachable from any route here. The DISPATCHER's demo skip reads the same `config.demo` flag and IS graded.
GET /api/slack/commandsIt counts the queue and answers an ephemeral line. It writes nothing, so there are no rows to grade.
GET /demoIt mints a session for the shared demo account and reseeds the shared demo book. DEMO_SUPABASE_PASSWORD is deliberately unset so the route answers 500 before touching anything, because a reseed of a shared account mid-run is a state change another environment would trip over.
triagedesk_postsRead by /blog and /changelog, written by nothing in the product.
POST /api/queue/[id] with action 'edit'`editDraft` is real and writes rows, but it is only reachable from the console's Edit control, which posts the thread id like every other control and answers 404. It is a route with no caller that can reach it, so it is recorded here rather than graded against a workflow nobody can run.

Findings

Defects the environment build found in the product itself.

0 open of 6
StateSeverityWhereWhat was found
fixedhighsrc/lib/live.ts (buildLiveConsole sets key: t.id) with src/components/Queue.tsx:86 and src/app/api/queue/[id]/route.tsEvery control on the console posts the THREAD id to a route keyed on the DRAFT id, so Approve, Edit, Kill and Take it back all answer 404 for any signed-in account. FIXED 2026-09-19: Row gained a draftId, buildLiveConsole sets it from the draft, and act() posts that. A press now answers 200 with status queued, measured through harness/look.mjs.
fixedmediumsrc/app/_lib/dispatch.ts (dispatchDue selects status='queued' only) with src/app/_lib/queue.ts undoDraftA reply claimed to `sending` can never be sent, failed, retried or taken back, and the console keeps drawing it as live. FIXED 2026-09-19: rail.replyTo is inside a try/catch so a throw fails the row with its reason, and dispatchDue finalises any claim older than 30 minutes as failed with sent_at null, reported as `reclaimed`.
fixedmediumsrc/app/_lib/inbox/rail-availability.ts, src/app/rails/page.tsx, src/app/dashboard/nav-map.tsrailConfigured(), railAvailability() and RAIL_UNAVAILABLE_NOTE have zero call sites, so the Connect control the module was written to fix is still a two-hop dead end. FIXED 2026-09-19: /rails calls railAvailability() and renders RAIL_UNAVAILABLE_NOTE in place of the Connect anchor when the rail's OAuth application is not registered.
fixedlowsrc/components/Chrome.tsx, src/components/Ledger.tsx, src/components/Queue.tsx, src/app/rails/page.tsx, src/app/settings/page.tsx. Fixed 2026-09-19 in triagedesk 1f7461e: the console model carries the connected provider, and every rail identity now derives its vendor mark, name and exact grant from that value.Every console surface names Microsoft 365 and its scopes regardless of which rail is actually connected
fixedlowsrc/app/_lib/slack/api.ts:45 via src/app/_lib/slack/deliver.ts replaceSlackCardslackPostTo() fetches a URL taken straight from the interaction payload with no host check, so a caller holding the signing secret can point an outbound POST at any host. FIXED 2026-09-19: slackPostTo refuses any url that is not https on slack.com or a subdomain, checked on a dot boundary so slack.com.evil.example is refused.
fixedlowsrc/app/api/integrations/oauth/[provider]/callback/route.ts:29-36The mailbox OAuth callback appends its error with a second '?' onto a path that already carries a query string, so every failure reason is swallowed into the view parameter and never reaches a reader. FIXED 2026-09-19: DEST already carries a query string, so both redirects append with '&'. Measured: /dashboard?view=integrations&connect=error&why=access_denied.