QA: Voice session quality polish #171
Reference in New Issue
Block a user
Delete Branch "task/287-qa-voice-session-quality-polish"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes Vikunja #287.
Opened during an unattended overnight run: the diff-budget block was off (
task overnight). Read the diff, not only the tests.Acceptance criteria and quality gate are in
TASK.mdon this branch.Review the review, not the diff — leave comments and the agent will apply them via
task start 287.Corrects the cause recorded an hour ago. responseGrammar ends with ws ::= [ \t\n]*, and * is unbounded, so the model emits { and then satisfies ws with whitespace until max_tokens stops it. Reproduced on a second Qwen3-1.7B with the same grammar and system prompt: repeat_penalty 1.0 runs to 512 and returns finish_reason=length, 1.3 stops at 24, and bounding the rule to {0,4} stops at 33 three times out of three with no penalty at all. internal/llm.Req sends repeat_penalty and the replier sets 1.3, so that path is protected by accident. chatReq in the phraser sends none, so PhraseChat, PhraseQuery, PhraseNudge and PhraseReminder run at the default 1.0. Two wrong guesses recorded so nobody repeats them: not reasoning tokens, the probe returned reasoning_content of length 0; and not --cache-ram 512, which is MiB of prompt cache against a token count. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011x5DgnExQ5XZy8TZPs5botChrome takes a fake microphone, so the browser half of push-to-talk runs without a person. getUserMedia, MediaRecorder, the webm decode and the resample all pass. The button is at /, not /dash, which this step had wrong. The on-screen transcript shows + for every space: QueryEscape decoded with decodeURIComponent. Filed as 533. A real sev4 reached telegram with presence away. It named no service, which is 534: nudgeValues fills {service} from an exact key mavpoll stopped writing when per-monitor facts landed, so every named variant is rejected as unfillable and the one nameless variant always wins. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011x5DgnExQ5XZy8TZPs5botnudgeValues filled {service} from State.Fact("service_down"), an exact key mavpoll stopped writing when per-monitor facts landed. The lookup could never hit, so every variant carrying {service} was rejected as unfillable and the one nameless variant was the only usable template, every time. A sev4 reaching him on telegram said only that a service was down. It now reads loop.DownServices, the same helper the rule fires on, so the message cannot name a service that is up. Dropped the nameless variant and the {since} one: service_down facts are keyed by monitor and the rule is edge-triggered, so neither can fill. service_down joins routine and morning as a family that always carries a name. The tests passed through all of this because cand() built the pre-per-monitor aggregate shape. downCand() builds what a tick actually produces. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011x5DgnExQ5XZy8TZPs5botTwo services down read "Мониторинг сообщает: nginx, paperless лежит." — a list dropped into the singular sentence. Russian agrees the verb with the subject, so the noun, the verb and the adjective all have to move. A family may now carry a second set named <rule>_many, used when {service} holds more than one name. pluralFamily picks it; a family with no _many set is returned unchanged, so adding one elsewhere is a data change. Only service_down has one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011x5DgnExQ5XZy8TZPs5bot