Document the withdraw_source Context action

SI
6d ago
+57-3

Summary

Documents the new withdraw_source action of the shared POST /api/context / MCP Context operation:

  • Request variant. request_id plus exactly one of source_id or source_version_id (a nested oneOf of required sets), with optional organization_id. source_version_id is what callers can already find on main, as sourceVersionIds in brief and saved-brief input manifests. The previous text wrongly said that source IDs appear in manifests.
  • Example. A withdrawSource example using a version ID.
  • 200 receipt shape. context-source-withdrawal-v1 with withdrawn_at, already_withdrawn, and affected = recorded lineage, which is identical on replay.
  • Behavior. Every result on the source is relabelled withdrawn (rows kept), documents whose current result used it lose it, and future reads, briefs and saved snapshots withhold that evidence. The withdrawal is sticky for the workspace, source kind and URL, so a later or in-flight job cannot republish it and ingestion that needs it accepted fails with a conflict. There is no restore.
  • 409. The description now says that withdraw_source has no idempotency key and can be retried unchanged.

This advances the CE08 Done-when item that withdrawn/private sources disappear from future authorized reads and derived briefs. The operate page is frontmatter-only and is unchanged.

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

Merge sequencing

docs → database → api → app. This is the contract-first PR. Sibling PRs on branch claude/ctx-2124-source-withdrawal: recoupable/database#102 (migration + transaction tests, including the late-writer fence) and recoupable/api#1008 (withdraw_source over HTTP and MCP). There is no app PR, because this slice has no UI. It does not depend on any open PR.

Known text conflicts:

  • Many open docs PRs (#357–#371) edit the same one-line operation description, so expect a trivial rebase.
  • Ticket #2125's docs#361 adds "source withdrawal … not exposed yet". Whichever merges second must drop that clause.

Verification

  • Ran: python3 -c "import json;json.load(open('api-reference/openapi/context.json'))": parses. The request-body oneOf lists ingest, read, brief, save_brief, read_brief and withdraw_source. The withdraw_source variant requires action and request_id, its nested oneOf requires source_id or source_version_id, and the withdrawSource example uses source_version_id. Edits were anchored text replacements, each matching exactly once.
  • Red → green: not applicable to a JSON contract change. The api PR's tests cover the documented input (including exactly-one identifiers) and the receipt shape. The database PR's tests assert every documented receipt key and type.
  • Not verified: Mintlify rendering of the nested oneOf, hosted deployment, live providers, production database.

Out of scope / known gaps

  • A restore/un-withdraw operation.
  • Scoped corrections, refresh or recomputation after withdrawal.
  • Duplicate-article corroboration rules.
  • Deletion/retention of original private bytes (owned by database#94/#95 + api#986–#991).
  • Cancel/refresh transports (#2125), workflows, paid calls, and any UI.

🤖 Generated with Claude Code