Document the typed Context error contract and lifecycle examples
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
codeenum equalscontextOperationErrorCodesinapi/lib/context/ContextOperationError.ts; the status named for each code in thecodedescription equalsstatusByCodeinapi/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$refsContextOperationError; theurlOnlyIngest,reconnectSameKeyandreadPartialResultexamples 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(-)againstmain). Nodocs.jsonnav change;api-reference/context/operate.mdxstays frontmatter-only. - Review corrections (commit 7c908f1):
storage_failedis 409 and not retryable (matches api#1005);unsupported_input(422) no longer claims album/playlist URLs, which fail schema validation with 400;readPartialResultnow 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;reconnectSameKeynow 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-linksnot 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
issuesand auth); only domain-operation failures use the typed schema.
š¤ Generated with Claude Code