Document the typed Context error contract and lifecycle examples

SI
5d ago
+136-3

Summary

Documents the typed error contract that the shared POST /api/context operation and the MCP context tool return (recoupable/api#1005). Adds components.schemas.ContextOperationError ({error, code, retryable, guidance} with nine codes), documents 402/403/404/409/422/500/503 responses against it, replaces the previously generic 409 with conflict, not_ready or storage_failed, and clarifies that 400 schema failures (including album, playlist or other non-track URLs sent to ingest) carry no typed code and surface as MCP InvalidParams. It publishes the agent-readable request examples the ticket names: URL-only ingestion, reconnect with the same idempotency key after a lost response, and reading a partial result. The operation description notes that the MCP error result sets isError: true, and that cancel, source withdrawal, scoped correction and selected-topic refresh are not exposed yet and will reuse this contract.

Refs recoupable/app#2125 (child of epic recoupable/app#2116).

Merge sequencing

docs -> database -> api -> app. This docs PR merges first (contract). No database change. Sibling api PR: recoupable/api#1005. No app change: the Chat proxy streams upstream status and body through unchanged.

Verification

  • Ran: python3 -c "import json;json.load(open('api-reference/openapi/context.json'))" -> parses.
  • Ran: an assertion script over this file and the api branch: the code enum equals contextOperationErrorCodes in api/lib/context/ContextOperationError.ts; the status named for each code in the code description equals statusByCode in api/lib/context/formatContextOperationError.ts (permission_denied 403, not_found 404, conflict 409, unsupported_input 422, not_ready 409, unavailable 503, budget_exhausted 402, storage_failed 409, internal 500); responses are 200/202/400/401/402/403/404/409/422/500/503 and each typed status $refs ContextOperationError; the urlOnlyIngest, reconnectSameKey and readPartialResult examples are present -> ok.
  • Edits were applied through a JSON round-trip that first asserted byte-identical output for the unmodified file (1 file changed, 136 insertions(+), 3 deletions(-) against main). No docs.json nav change; api-reference/context/operate.mdx stays frontmatter-only.
  • Review corrections (commit 7c908f1): storage_failed is 409 and not retryable (matches api#1005); unsupported_input (422) no longer claims album/playlist URLs, which fail schema validation with 400; readPartialResult now says a partial request is final for its idempotency_key (re-sending the original body returns it unchanged) and that a new key re-collects while reusing identical saved evidence; reconnectSameKey now says a queued, running or failed request is re-dispatched, with the claim lease preventing duplicate concurrent execution, instead of "without dispatching new provider work".
  • Red -> green: not applicable to docs; api#1005 cites its RED runs.
  • Not verified: Mintlify hosted render (npx mintlify broken-links not run), hosted deployment, live providers, production database.

Out of scope / known gaps

  • cancel, source withdrawal, scoped correction and selected-topic refresh are not documented as actions (owned by #2122 / #2124); only the note that they will reuse this error contract.
  • The example Spotify track ID is a syntactically valid placeholder, not a real recording.
  • 400 and 401 keep their existing bodies (validator issues and auth); only domain-operation failures use the typed schema.

šŸ¤– Generated with Claude Code