Skip to content

superhuman: draft-management commands fail against live backend (drafts list 400, get empty, discard 520) #1303

Description

@noahlevin

superhuman: draft-management commands fail against the live backend

The superhuman CLI's draft-management surface does not interoperate with the current Superhuman backend. Reads (Gmail passthrough: messages list, messages query) and threads list work fine, and drafts new returns 200 — but drafts list, drafts get, and drafts discard all fail. Because drafts new "succeeds" while the read/list/discard paths fail, created drafts are effectively unmanageable.

Environment

  • superhuman-pp-cli built from library/productivity/superhuman (pseudo-version v0.0.0-20260618052343-6f215c39f277, runtime 2026.6.1)
  • Auth via auth login --disk (windowless Chrome-session mint — works well)
  • Verified live against a real Superhuman account on 2026-06-18 and 2026-06-20 (identical results both days, so not a transient outage)

1. drafts list → HTTP 400 (root-caused + fix in PR)

$ superhuman-pp-cli drafts list --account <me> --agent
Error: POST /v3/userdata.getThreads returned HTTP 400: {"code":400}

Root cause: internal/cli/drafts_list.go posts an empty {} body to /v3/userdata.getThreads. The backend's BackendListFetcher requires a {filter:{type:"draft"}} discriminator — the exact lesson internal/cli/threads_list.go already encodes as PATCH(U3) (empty {} returns HTTP 400 from the backend). threads list --type draft (which sends that shape) succeeds live; drafts list 400s only because it never got the same shape.
Fix: send {filter:{type:"draft"}, limit, offset}. Verified live (released binary → 400; patched → 200 with the full draft threadList) + regression test. See PR.

2. drafts get <id> → empty / not-found

$ superhuman-pp-cli drafts get <draft-id> --account <me> --agent
Error: drafts get: <draft-id> not found

/v3/userdata.read returns no draft body in any of the wrapper shapes unmarshalDraftValue tries, even for a draft that exists (visible in threads list --type draft and in Gmail in:drafts). Note drafts get/readDraft build users/<uid>/threads/<draft-id>/messages/<draft-id>/draft reusing one id for both the thread and message segments, whereas real drafts have distinct thread-id vs message-id segments (e.g. threads/draft007cf1…/messages/draft00f93…) — a likely contributor. Needs the live userdata.read draft contract to fix confidently.

3. drafts discard <id> → HTTP 520

$ superhuman-pp-cli drafts discard <draft-id> --yes --account <me>
Error: POST /v3/userdata.write returned HTTP 520: {"code":520,"detail":"server-error"}

Persistent across ~10 retries over several minutes, on two separate days. drafts new uses the same userdata.write endpoint and returns 200, so the discard tombstone payload specifically is rejected at origin. Needs the live userdata.write delete/tombstone contract.

Secondary (separate bug): time-bomb test

internal/cli/send_test.go TestSendDryRun_ScheduleAt fails once the hardcoded 2026-05-20T08:00:00Z schedule date is in the past (send: --schedule-at must be in the future). go test ./... is red on main for this reason as of 2026-06-20. Worth switching to a relative future offset.

I've opened a PR for #1. Happy to help reproduce #2/#3 if useful, but they need the real backend contract to fix correctly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions