Discover the contract
GET /coaching/capabilities requires project_todos:read but deliberately does not require feature enablement, a claimed account, or a job. It returns static operation, scope, limit, export, image, event, and typed-error facts without tenant data.
Employer reads
These endpoints require
project_todos:read, employer access to the job, and a claimed account. Names are masked; emails and answer keys never appear.
Draft and apply employer feedback
Employer coaching mutations usePOST /manage with project_todos:write and a stable idempotencyKey:
The plan action is keyless and requires only
project_todos:read; nothing becomes worker-visible until confirm. Any changed selection, draft, submission, or review state makes confirm fail closed with 409 PLAN_STALE.
Worker lane
Workers mint the separateproject_todos:respond scope from their own settings. Employer API keys — including Full access — cannot receive or use this scope.
Autosave rejects changes to answers outside the requested set and uses
expectedRevision as an optimistic lock. Worker responses never include answer keys, correct values, scoring rules, other workers, or private employer drafts.
Feedback images
Images use a three-step private lifecycle under/coaching/{assignmentId}/assets: prepare a deterministic reservation and short-lived single-PUT grant, upload bytes directly with upsert disabled, then finalize after server-side size, type, and SHA-256 verification. Status and delivery endpoints return lifecycle facts or a short-lived delivery link.
Never log or persist the upload grant. Bytes do not belong in JSON or base64 request fields. If an upload outcome is ambiguous, retry through canonical finalize/status reconciliation rather than requesting a different object path.
Full retakes
To reopen the entire quiz, userequire_retake_plan and require_retake_apply. Those checksum-bound actions are intentionally separate from selective coaching.