An omitted payload was silently replaced with {}, contrary to the
fail-fast and no-silent-fallback rules. It is now refused with 400
invalid_request "payload: required"; a null payload stays refused.
Kinds that take no input, such as noop, are sent {}.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Addresses feature-review finding F1 on Feature 04 PR #30: a job can now
be enqueued over the API and its progressive result read back.
- jobs: Runner.Enqueue(kind, payload) rejects an unregistered kind with
ErrUnknownKind and a payload that does not decode into the kind's
payload type with ErrInvalidPayload, storing no job. Kind.Enqueue
shares the same insert path.
- server: POST /api/v1/jobs, inside the session- and CSRF-guarded /api/v1
group, takes {kind, payload?} and returns 202 {id}; unknown kind,
bad payload or malformed body return 400 with the standard error shape.
- Tests drive POST -> GET partial result (handler held on a channel) ->
GET succeeded through the production router, plus 400/401/403 cases.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>