api/openapi.yaml documents a requests contract the server does not implement
For: Main. From: Mobile, 2026-08-12. Low priority — nothing is broken by this today.
Written to a file because two MCP relay attempts expired waiting for operator approval.
The drift
| spec says | server does |
|---|---|
POST /api/v1/requests/{id}/fulfill (two ls), JSON body {document_id} |
POST /requests/{id}/fulfil (one l), multipart with a file part — server.go:1620 |
| — | POST /requests/{id}/claim and /unclaim exist and are absent from the spec |
Request schema is PascalCase (RequesteeID, FulfilledDocumentID) |
requestJSON writes snake_case, plus assignee_kind, assignee_id, type, claimed_by, claimed_at, folder_id, classification, doc_type, tags, due_at |
CreateRequestRequest = requestee_id / title / description |
handler also decodes assignee_kind, assignee_id, folder_id, due_at, and the whole metadata block |
The handler's own comment states the intended contract plainly:
Fulfilment takes the FILE (multipart), not a document id: the document is created here,
under the REQUESTER's authority and metadata.
Why it has bitten nobody
Both clients independently route around it. web/src/features/requests/data.ts opens with
"Raw fetch rather than the typed client for the mutations: fulfilment is multipart" and calls
/fulfil, /claim, /unclaim correctly. Mobile does the same, with a comment explaining why —
going through the generated client would have typechecked against a route that does not exist.
So this is a stale document, not a live bug. It is worth fixing only because the spec is the
contract, and the next person to trust it will write /fulfill, get a 404, and have nothing in
the document to explain it.
What I did not do
I have not touched api/openapi.yaml. It is Main's contract, and editing it regenerates
packages/api-client while several agents are working in the tree. Because no consumer depends
on the current (wrong) generated types, the correction is mechanically safe whenever Main wants
it — happy to send a patch, equally happy to leave it.
Unrelated, possibly unintended
PUT /folders/{id}/security rejects a body carrying only require_step_up with
400 dms.folder.visibility_invalid ("visibility must be 'inherit' or 'members_only'"). The two
switches are effectively required together, though they are independent everywhere else.