Sub-issue of #565 (master: HydraNPS end of experience rating). Full design on #565. This issue is Phase 3: hydraheadflatscreen agent + Qt kiosk (hydra-experiencenet).
Scope, agent first:
- Session id mint (<head_id>-), stream start timestamp, pending rating with compare and swap + hard expiry (submits score:null and releases the isStreamIdle guard if the Qt app never answers)
- source field on POST /api/v1/stream/stop (default operator); end_reason labelling in one place
- POST /api/v1/rating local route; JSONL offline queue /nps_queue.jsonl flushed on Client.tick() via /api/v1/ratings/batch (drop after 24 h or 1000 lines)
Then Qt kiosk:
- quitStarting push for visitor exits; source: visitor on the overlay stop body
- Rating card per docs/design/rating-card.md in the kiosk grid process (KioskView.qml, help dialog pattern); Linux in process and macOS subprocess paths; cancel the 10 s timer on star tap
- Old/new tolerance both directions: 404 on /rating/show submits score:null; bodiless stop is operator, no card
Verify on chunky-turnip-23 (bxl1-test) with cheeky-cactus + cosmic-pretzel-98: visitor exit shows card once; stream-stop CLI shows NO card, end_reason shutdown; kill Qt between /rating/show and reply, confirm score:null lands and updates not blocked.
Depends on: hydranps and hydracluster sub-issues.