N2 and N3, no contract doc
// All error responses share one shape: { error: { code, message, details? } }
GET /projects/nope/tasks → 404
{ "error": { "code": "not_found", "message": "Project not found" } }
This is a common, well-designed envelope. It is also exactly what the v3.x apps cannot read: body.error is now an object, so users see an empty red banner and a retry button that does nothing. Nothing in the code told the agent the apps existed.
V1, same prompt, contract doc present
// Every error response has the shape:
// { error: string, code: string, requestId: string, details?: [...] }
// `error` must stay a human-readable string: mobile v3.x displays it verbatim
// (see docs/mobile-contract.md). Clients should branch on `code`, not `error`.
Same one-line prompt. The agent found the doc, kept error a string, added code beside it, and echoed the request ID, which the doc only mentioned in passing.