Tonight's work as one branch: all 46 reviewed PRs, verified green #47
Reference in New Issue
Block a user
Delete Branch "integration/jul31"
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?
Everything from tonight, on one branch, verified as a unit. Replaces the 46 stacked PRs — you reviewed the content already, this is the same content with the topology problems taken out.
135 commits.
make buildproduces all 8 binaries.make testexits 0: 38 packages, no failures, no data races, gofmt and vet clean.Why one PR
42 of the 46 PRs were already ancestors of
overnight/resident-1.7b. Only 7, 41, 43, 44 sat outside it, and 44 already carried 41. So the whole tower was three merges, not a 46-way restructure.Contains all 46: verified by ancestry check, every PR head is an ancestor of this branch.
What had to be fixed to make it build as one thing
internal/store/migrations.go— merging PR7 conflicted. Migration#8(idx_nudges_snoozed) was already present byte-identical, so PR7's content was fully absorbed; resolved to the existing version, nothing lost.gofmt— PR41 and PR44 landedinternal/kiwix/client.goandrewrite_test.gounformatted. The gate PR12 added tomake testfailed the moment both were on one branch. Struct-tag and comment alignment only.MODEL-BAKEOFF-31-07-2026.md— the file led with "Recommendation: keep Qwen3.5-0.8B" while ending with the switch to Qwen3-1.7B, and contradictedCLAUDE.md. Both sweeps are accurate, so nothing was rewritten: the lede now states the outcome and the first sweep's verdict is scoped to what it actually tested (it rejects LFM2.5-1.2B, which still holds).Still open, deliberately not done here
Your review comments on PR4 (
ipc/server.goat 947 lines with 43casearms;mavweb/main.goat 1296 lines of HTML-in-Go) are pre-existing debt these changes sit on top of, not something they introduced. Refactoring it mid-merge would have made this unreviewable. It wants its own task.Also unaddressed: the Russian wording notes on 6/21/23 (
"На какое время"/ plain"Когда?","тепло", the persona hand-leak, ~5 timeout phrasings instead of one) and your questions on 3 and 15. Say the word and I'll do them as a follow-up on master.PR1's six comments are answered — review #37 on that PR. All six are genuinely fixed by PR22, which was written to answer them; they were a pair.
Note PR44's own body says its score shows the Kiwix rewrite does not work yet. It is included because external search is off unless configured, but it is not a working feature.
The system prompt showed the JSON contract as {"response": "..."} and the user prompt repeated it. A 0.8B copies whatever sits in the response slot, so 7 of 15 nudges came back as literally "...". Changes, all prompt-side — the {"response","mood"} contract is unchanged: - nudge system prompt is Russian, feminine self-reference, with filled-in examples on topics that never appear as rules, so copying them is visible - rule names get a Russian gloss and a required keyword, named last in the prompt where a small model weights it hardest - durations render in Russian, not English - the no-parse fallback says something Russian instead of "water — care", which was going straight to a Russian piper voice - same "..." placeholder removed from replier_llm.go Scored on internal/phraser/eval: 0/15 -> 13/15. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CGeSZxh1DCtRxmFVSYVGvJThe prompts stated the feminine self-reference rule but never said whom she is speaking to, so the model produced formal plural ("Жду вас") and talked about him in third person ("Он не ел 11 дней"). Adds the address rule right next to the feminine one, in the nudge prompt and the confirmation prompt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CGeSZxh1DCtRxmFVSYVGvJTwo bugs, one symptom. A run of the talk eval produced replies that were literally "{" and "{\n \"" — those strings went out as things Maven said. First bug: the parser could not tell "the model answered in plain prose" from "the model started a JSON object and got cut off". Both came back as empty, and every caller then shipped the raw text. Now an unfinished object returns an error and each caller uses its own fallback instead. Bare prose with no JSON in it still passes through, because small models do sometimes answer that way and the reply is fine. Second bug, and the actual cause: the grammar capped the response field at 400 characters. I measured it against Qwen3.5-0.8B at three different token caps — 256, 768 and 2048 — and the reply came back exactly 400 characters every time, cut mid-word. So the token limit was never what stopped it. The bound is 1000 now, about six Russian sentences, still low enough to cut off a repetition loop. Token caps go from 256 to 768 on the chat and query paths so 1000 characters of Russian actually fits. The nudge path keeps its own cap; a nudge is meant to be one sentence. Note: cmd/mavend/replier_llm.go has its own copy of this parser with the same bug. Left alone here so this commit stays small — that duplicate is Vikunja #396. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CGeSZxh1DCtRxmFVSYVGvJIt scored 27/27 on a run where two replies were "{" and "{\n \"". It only tested that the string was not blank, so punctuation counted as content and the worst replies of the run passed the first check. Now a reply needs at least one letter, Cyrillic or Latin. Latin counts because answers about ssd or vpn are legitimately part English. Digits alone fail too. The same run answered "сколько варить яйцо вкрутую?" with "15-16" — no unit, no words, and the wrong number as well. That is not something she said. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CGeSZxh1DCtRxmFVSYVGvJNudge wording as data instead of generation. The wording lives in internal/phraser/nudges_ru_v1.json (embedded), about 10 variants per rule: water, meal, break, service_down, netdata_critical, routine:, morning:, plus a contentless default. That JSON is long because it is data — the owner can edit any line of Russian without touching Go. The picker: - random, but never the same variant twice in a row for the same rule - deterministic when seeded (math/rand with an injectable source) - fills {since} / {service} / {what} from the candidate, and skips any variant whose value is missing, so no raw placeholder can reach the piper voice - {since} is spelled out in words ("полтора часа", "семь часов"), because "3 ч" is wrong in a Russian voice Scores 15/15 on the existing nudge fixture, on every seed swept. Nothing is wired yet — that is the next commit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CGeSZxh1DCtRxmFVSYVGvJKiwix ranks by keyword, not meaning, so a translated question finds song and TV titles. This asks the resident model for the TOPIC instead: a short English noun phrase, like a Wikipedia article title. Locked down three ways, because a wrong query is silently wrong: - A GBNF grammar, same idea as routeGrammar and responseGrammar. The reply must be {"query":"..."} with Latin words only. The JSON wrapper matters: this model always thinks out loud and this llama-server build ignores the thinking switch, so a bare word-list grammar just captured "Let me analyze this request carefully" for every question. - max_tokens 32, since the answer is a few words. - CleanQuery, which throws away empty, Russian and prose replies rather than passing them to Kiwix, and drops question words like "why" and "how much" that a keyword ranker cannot use anyway. Client side only. Nothing is wired into the daemon or any config. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CGeSZxh1DCtRxmFVSYVGvJ