Skip to content

Migrate writes from /api/ops to RPC (tarpc) #207

Description

@rawkode

Background

User clarified the v3 north star: all reads via GraphQL (kernel + federated extensions, tracked in SP6 #203), all writes via RPC (this issue). The frontend never calls /api/ops directly.

Currently /api/ops carries BOTH read and write traffic for extensions. SP6 handles the read half; this issue handles the write half.

Target transport: tarpc

https://github.com/google/tarpc

Why:

  • Typed request/response shapes — matches the WIT input records we already have.
  • Async-friendly; embeds in axum alongside the GraphQL endpoint.
  • Bidirectional streaming hook for writes that need progress feedback (large imports, multi-step migrations).
  • One sub-second transport for the whole write surface instead of N JSON-over-HTTP endpoints.

Scope (writes)

Every WIT op that is a write today migrates to a typed tarpc method:

  • ext_issues: open-issue, close-issue, reopen-issue, assign-project, post-comment, edit-comment, delete-comment
  • ext_epics: create-epic, change-state-epic, assign-project
  • ext_pull_requests: create-pull, close-pull, merge-pull
  • ext_checks: record-check
  • ext_docs / ext_workspace_home: any write ops that exist today
  • Kernel writes currently exposed via /api/ops (label updates, repository config, etc.)

Out of scope (stays on existing transports)

  • Git smart-HTTP push (receive-pack) — already pure Rust, not an extension write.
  • OIDC callback / token exchange — kernel-internal HTTP.
  • Webhook / publisher fan-out — emitted via the event log.

Build outline

  1. Spec + spike: typed Rust trait shape, how the WASM component answers the tarpc method (custom WIT export, similar in flavour to SP6's graphql-resolve), auth threading, error mapping, idempotency keys.
  2. Generated codegen: extend comtrya-wit-codegen so every WIT write op gets a tarpc method emitted from the same source.
  3. Server: stand the tarpc service up alongside axum, wire into the same auth + rate-limit + audit pipeline.
  4. SDK rollout: typed RPC client per extension in @comtrya/sdk-core. Frontend write callers (createEpic, closeIssue, mergePull, etc.) migrate one by one.
  5. Sunset /api/ops writes: once every write caller is on tarpc, the /api/ops POST surface is removed.
  6. Tests + docs: per-extension write test suite, end-to-end RPC flow in start.sh --reset --oneshot, updated SPEC.md / GOAL.md / v3-decisions.md to describe RPC as the live shape (not the goal).

References

  • docs/spec-gap-analysis.md §A7.1 — RPC writes (decided)
  • docs/v3-decisions.md — north-star section
  • GOAL.md — north-star section
  • SPEC.md — product principles
  • AGENTS.md / CLAUDE.md — WIT / Extension / Protocol Rules
  • SP6 SP6: rebuild Apollo Federation v2 (v3 north star) #203 — federated GraphQL reads (parallel migration)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions