- Shipped
- August 27, 2026 at 7:42 AM UTC
- Author
- Kamo
- Commit
- 8f7cf0d
**************** — list, get, update, and PATCH status. Copies ServiceTaskBookController's idiom: orgId(req) or 401, a right check or 403, a String path variable through parseUuid or 400, and one failed() helper splitting the service's IllegalArgumentException into 404 for a missing row and 400 for everything else. A missing job is a 404 to match every sibling handler — the detail page renders its not-found state off that code, and a 400 there would hide 'no longer exists' behind 'your request was malformed'. A refused status transition is a well-formed request against a job that exists, so ServiceJobStatusMachine's message naming both states reaches the client as a readable 400. Reads take VIEW_SERVICE_WORK and writes take MANAGE_SERVICE_WORK, which is a CHILD of VIEW in the rights tree — so a write that settled for VIEW would be a silent downgrade that still looked gated in review. The gate test calls every write with a view-only session to prove it does not happen. The test drives the real handlers rather than grepping the source. ServiceTaskBookRightsGateTest says in its own javadoc that a source scan 'cannot prove the check runs before the work'; BaseLosController resolves the session from a request attribute, so a MockHttpServletRequest carrying a rights list is enough to read the real status code back — and to assert the service was never reached, which is the half a scan cannot see: a handler that acts and then checks returns 403 having already written the row. Mutation-tested: the manage right swapped for view, a right check deleted outright, the right check moved after the service call, failed() flattened to always-400, PATCH /status turned into PUT, and the session's org replaced by a literal. Each produced a distinct failure naming the handler at fault.