- Shipped
- October 4, 2026 at 7:28 PM UTC
- Author
- Kamo
- Commit
- 776433e
SP96 Task 10 (spec §5.5): - GET **************** the router's TTS candidates for the AI (actor AI with the member; never AiCallRuntime.guard, so a paused or retired AI reads), those a speech adapter serves, preferred model first: E5's walk. Each model has its remembered voice, decide()'s next voice with nothing written, and the compatible voices best tier first; rows on models not offered are listed unavailable. - PUT **************** {voiceId?, preferred?}: a CHOSEN voice (the caller, the sex at pick), then the model used first, in one transaction (MemberVoiceWriter, @Transactional @RetryOnDbConflict, no HTTP). Preferring a model with no row remembers E5's first pick there, unspoken. - GET **************** the same view, canChange false, behind X-Internal-Auth (InternalCaller). - Read: MANAGE_MEMBERS, MANAGE_MEMBER_SECURITY, MANAGE_AI_WORKFORCE, VIEW_AI_WORKFORCE, or SUPERVISE_AI_MEMBERS as its supervisor. Change: MANAGE_AI_WORKFORCE, or its supervisor with SUPERVISE_AI_MEMBERS. Never the AI itself. Refusals MISSING_RIGHT, MEMBER_NOT_FOUND, MODEL_NOT_AVAILABLE, VOICE_NOT_OFFERED, VOICE_NOT_COMPATIBLE, RETIRED. - AiAccessRules: /api/ai/members/** is a member route; the controller decides.
