Risk tiers: take Hexis's tier for a Hexis capability, derive only for local tool rows #162
Closed
claude
wants to merge 33 commits from
task/523-risk-tiers-take-hexis-s-tier-for-a-hexis into task/449-destructive-confirm-policy-risk-tiers-no
pull from: task/523-risk-tiers-take-hexis-s-tier-for-a-hexis
merge into: kami:task/449-destructive-confirm-policy-risk-tiers-no
kami:master
kami:task/725-capability-ledger-and-empirical-baseline
kami:task/692-heads-path-may-equal-model-path-and-noth
kami:task/694-staticcheck-and-deadcode-are-still-not-i
kami:task/682-go-1-25-5-and-x-text-0-14-0-carry-20-rea
kami:task/674-caveats
kami:task/673-mavgpud-serves-the-model-to-the-whole-la
kami:task/487-capture-device-doc
kami:task/487-capture-device
kami:task/487-wake-word-deploy
kami:task/487-wake-word-threshold
kami:task/487-wake-word-stage-two
kami:task/671-mavwaked-registers-as-a-voice-consumer-i
kami:task/670-cut-claude-md-to-200-lines
kami:task/515-deploy-mavwaked-workpc
kami:task/669-prune-claude-md
kami:task/668-e4b-phrasing
kami:task/668-title-capital
kami:task/668-kiwix-answers-a-question-it-cannot-answe
kami:task/666-only-a-stage-0-grammar-may-take-the-pers
kami:task/487-mavwaked-has-no-wake-word-only-an-energy
kami:task/486-deploy-the-workstation-transcriber
kami:task/486-move-stt-and-tts-to-the-workstation-wher
kami:task/665-crisperwhisper-2-russian
kami:task/664-routing-heads-in-go
kami:task/662-usage-harness-source-badge
kami:task/661-post-merge-usage-rerun
kami:task/661-routing-heads-step-3-train-the-multi-hea
kami:task/660-router-prompt-destination
kami:task/659-destination-fixture
kami:task/655-query-source-is-a-routing-decision-made
kami:task/654-a-pending-clarify-has-no-way-out-neither
kami:task/654-week-of-usage-eval-docs
kami:task/649-needs-kami-telegram-is-the-only-reach-an
kami:task/643-memorystore-search-decodes-and-unmarshal
kami:task/641-two-maps-grow-for-the-process-lifetime-w
kami:task/644-mavcaldav-is-built-documented-as-running
kami:task/642-the-store-caps-sqlite-at-one-connection
kami:task/647-factenrichmentworker-walks-the-pending-q
kami:task/646-v-637-follow-up-telegram-intake-has-no-d
kami:task/638-no-deadline-survives-the-turn-path-from
kami:task/637-inbound-telegram-turns-and-corrections-f
kami:task/636-correcting-a-turn-from-telegram-and-from
kami:task/634-an-act-alias-resolves-the-verb-but-not-t
kami:task/630-one-gesture-correction-on-chat-v-628
kami:task/629-persist-the-routing-trace-and-record-it
kami:task/631-mode-inventory-written-from-the-handlers
kami:task/586-defaultfactparser-uses-hand-written-russ
kami:task/633-reconcile-the-seed-labels-with-the-handl
kami:task/627-reminder-verbs-has-no-alarm-verb-so-an-a
kami:task/626-the-classifier-seeds-teach-an-older-inte
kami:task/546-route-with-a-fine-tuned-e5-small-instead
kami:task/586-measure-the-fact-parser
kami:fix/gofmt-ecosystem-acts
kami:task/584-media-store-a-failed-write-leaks-its-bud
kami:task/518-no-write-path-for-a-backdated-event-so-t
kami:task/287-qa-voice-session-quality-polish
kami:task/492-qa-plan-reconcile
kami:task/530-sweep-tail-four-files-the-russian-sweep
kami:task/405-score-how-often-a-real-utterance-reaches
kami:task/529-money-and-list-pick-a-mechanism
kami:task/528-sweep-tail-the-three-files-on-467
kami:task/527-embedder-open-set-phrasings-stop-being-r
kami:task/526-morphology-a-dictionary-answers-the-gram
kami:task/525-lexicons-the-finite-russian-sets-move-to
kami:task/524-entity-reference-ask-nexus-about-every-l
kami:task/521-review-pr-111-query-strings-declension-h
kami:task/491-llama-server-core-dumps-on-every-sigterm
kami:task/479-bug-an-unconfigured-capability-does-not
kami:task/467-bug-spoken-task-capture-is-dead-the-rout
kami:task/463-deploy-mavwaked-and-mavenclient-run-nowh
kami:task/480-hearing-no-shipped-client-can-start-a-re
kami:task/432-ambient-calendar-intake-is-fragile-and-p
kami:task/431-board-surface-maven-holds-the-work-board
kami:task/433-reactivehandler-has-30-fields-and-is-pas
kami:task/371-swap-the-embedder-for-an-asymmetric-retr
kami:task/408-review-31-07-split-the-30-method-coreapi
kami:task/410-review-31-07-hand-rolled-string-enums-st
kami:task/423-review-pr50-split-internal-ipc-server-go
kami:task/422-review-pr50-split-cmd-mavend-tick-go-860
kami:task/409-review-31-07-finish-moving-mavweb-markup
kami:task/482-ambient-ingest-reads-a-notification-s-ti
kami:task/444-kuma-a-fact-per-monitor-so-she-can-name
kami:task/452-capability-model-homelab-docker-restart
kami:task/449-destructive-confirm-policy-risk-tiers-no
kami:task/453-grocery-list-items-table-fourth-append-o
kami:task/399-run-the-persona-checks-inside-the-daemon
kami:task/448-bounded-follow-up-state-pending-candidat
kami:task/455-conversation-repair-name-the-misroute-co
kami:task/454-go-mod-tidy
kami:task/458-pronunciation-dictionary-for-piper
kami:task/456-command-history-read-only-query-over-exi
kami:task/457-clarification-templates-for-the-router-s
kami:task/474-query-source-ordering-feeds-and-calendar
kami:task/469-reminders-spelled-out-times-fail-the-bod
kami:task/475-bug-the-praxis-attention-capability-is-u
kami:task/481-bug-a-transient-complaint-is-stored-as-a
kami:task/476-bug-the-router-transliterates-latin-enti
kami:task/385-decide-whether-a-parked-clarify-question
kami:task/377-backfill-routines
kami:task/421-weather-geocoder
kami:task/390-no-read-path-for-delivery-attempts
kami:task/386-recall-fixture-filler-note-ids
kami:task/473-bug-morning-item-has-no-required-flag
kami:task/465-bug-make-simulate-routes-with-an-empty
kami:task/467-bug-spoken-task-capture-is-dead
kami:task/466-bug-a-pending-clarify-is-global-so-one-u
kami:task/468-bug-pattern-detect-has-no-minimum-interv
kami:task/462-bug-checkfeminine-flags-second-person-ma
kami:task/443-safekey-drops-cyrillic-so-russian-calend
kami:task/471-bug-agendaquerygrammars-covers-today-but
kami:task/383-slottext-in-clarify-answer-would-clobber
kami:task/323-qa-phraser-coverage-is-65-3-but-the-llam
kami:task/498-bug-and-x-reach-the-model-with-no-determ
kami:task/506-strings-family-6-summaries-and-reports-i
kami:task/504-strings-family-4-act-and-smart-home-repl
kami:task/503-strings-family-3-query-answers-and-gaps
kami:task/502-strings-family-2-capture-acknowledgement
kami:task/501-strings-family-1-phrasing-fallbacks-into
kami:task/397-phrasechat-and-phrasequery-hide-model-fa
kami:task/396-the-reply-path-can-t-be-tested-llmreplie
kami:task/496-recall-a-cross-language-question-loses-i
kami:task/495-bug-x-escapes-the-personal-boundary-and
kami:task/499-llama-server-holds-7-9gb-rss-for-a-1-1gb
kami:task/470-bug-a-question-writes-invented-knowledge
kami:task/493-bug-the-memory-index-stores-the-raw-utte
kami:task/490-name-the-gap-world-questions-through-the
kami:task/485-run-the-big-model-on-the-workstation-wit
kami:task/489-workstation-deploy-mavgpud-on-workpc-and
kami:task/488-workstation-a-supervisor-that-keeps-llam
kami:task/483-docs-offload-design
kami:task/483-design-offload-ml-to-the-workstation-kee
kami:task/459-docs-refresh-the-qa-plan-against-the-liv
kami:task/446-doc-reorg-tier-the-tree-retire-the-three
kami:fix/367-voice-parks-routine-accept
kami:task/365-dialogue-slots-and-router-slots-are-hand
kami:task/364-snooze-does-nothing-at-runtime-the-gate
kami:task/447-retire-progress-md-the-backlog-and-the-f
kami:task/445-session-workflow
kami:overnight/eco-versioned-traces
kami:overnight/eco-entity-refs
kami:overnight/eco-degraded-suite
kami:overnight/netscan
kami:overnight/smarthome
kami:overnight/replay-simulator
kami:overnight/event-envelope
kami:overnight/coldstart-unlock
kami:overnight/voice-barge-in
kami:overnight/stt-golden-audio
kami:overnight/senses-speaker
kami:overnight/senses-hearing
kami:overnight/senses-media-vision
kami:overnight/mcp-tools
kami:overnight/mcp-client
kami:overnight/self-update
kami:overnight/model-swap
kami:overnight/web-crawler
kami:overnight/rss-feeds
kami:overnight/email-poller
kami:overnight/email-extract
kami:overnight/email-imap
kami:overnight/money-zenmoney
kami:overnight/task-priority
kami:overnight/task-capture
kami:overnight/behavior-profile
kami:overnight/day-plan
kami:overnight/ambient-calendar
kami:overnight/local-calendar
kami:overnight/memory-eval
kami:overnight/proactive-proposals
kami:overnight/split-voice-quiet
kami:overnight/nginx-maven-block
kami:overnight/stepup-chat-surface
kami:integration/small-batch
kami:docs/fix-drift
kami:fix/ru-wording
kami:integration/jul31
kami:overnight/resident-1.7b
kami:overnight/nudge-templates
kami:overnight/kiwix-rewrite
kami:overnight/eval-writeup
kami:overnight/fix-truncation
kami:overnight/kiwix-client
kami:overnight/ru-prompts
kami:overnight/external-data
kami:overnight/phrasing-grammar
kami:overnight/talk-eval
kami:overnight/prompt-context
kami:overnight/prompt-address
kami:overnight/eval-label-kill
kami:overnight/delivery-boundary
kami:overnight/address-check
kami:overnight/system-replies-pr
kami:overnight/clock-intent-pr
kami:overnight/embedder-backfill-pr
kami:overnight/embedder-marker-pr
kami:overnight/note-recall-pr
kami:overnight/thinking-off-pr
kami:overnight/dialogue-persist-pr
kami:overnight/persona-2p-pr
kami:overnight/clarify-expiry-pr
kami:overnight/clarify-rework
kami:overnight/phrasing
kami:overnight/bakeoff
kami:overnight/recall-margin
kami:overnight/router-on
kami:overnight/slot-extract
kami:overnight/embedder-e5
kami:overnight/router-refusal
kami:overnight/eval-rerun
kami:overnight/eval-harnesses
kami:overnight/eval-rerun-base
kami:overnight/fmt-gate
kami:overnight/routines-fire
kami:overnight/router-prompt
kami:overnight/away-leak
kami:overnight/recall-eval
kami:overnight/snooze-works
kami:overnight/clarify-wiring
kami:overnight/delivery-tests
kami:overnight/routine-accept
kami:overnight/llm-router-flag
kami:overnight/clarify-data-layer
kami:overnight/loop-rule-tests
33 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
0ade0ec734 |
tool, mavend: Hexis owns the tier of a Hexis capability (V-523)
read_only was the whole decision on the Hexis act path, which flattened three answers into two. A capability that wipes the thing it names got the same single spoken "да" as one that restarts a service, and requires_confirmation — which the Hexis contract calls server-derived and never settable by a caller — was read by nobody. docs/ecosystem.md §17.3 says confirmation follows risk. RiskOfCapability reads Hexis's risk, read_only and requires_confirmation and returns one of the three tiers internal/tool already had. It takes plain values rather than a Capability, so internal/tool keeps no dependency on the Hexis client. RiskOf keeps deriving, because a shell row the owner ticked on /tools has no upstream to ask. Every disagreement between the three fields goes up, never down: safe and mutating is a contradiction and takes the confirm, an unrecognised tier takes the confirm, and requires_confirmation may only raise. Same default as an unrecognised dispatch shape — argue your way down, never up. The irreversible refusal was a Go literal in two places and is now one deck entry, act_needs_authed_surface. It lost four words to the persona ceiling. |
||
|
|
d960e211d3 |
Merge task/449 into the risk-tier fix branch (V-523)
Brings internal/tool/risk.go in so the Hexis split can be written against it. Four conflicts, all additive: both grammar sets in voicewire.go, both test sets in agenda_test.go and stage0.go, and in actions_act.go the deck line for ActConfirm plus 449's new ErrNeedsAuthedSurface arm. Two renames the merge forced. actions_list_test.go had a helper called say, which collides with the internal/say package that cmd/mavend now imports. actions_act_risk_test.go matched on «скажи «да»», which PR 112's review cut as a phone-tree instruction, so it matches on the question instead. --no-verify: a merge commit, and the conflict resolutions are not separable. |
||
|
|
6fba4d6931 |
say: one count rule everywhere, and a page she can explain (V-521)
The PR 113 review found four defects in one line file. Swept the other four families and the Go side for the same four. The JSON was clean: no undeclared placeholder, no abbreviation spoken, no single-variant entry left unfixed. One register leak — page_blocked read "robots.txt" out loud, which is a filename, not a reason he can act on. The count rule was not clean. Four more copies of the three-way agreement existed and two of them were wrong: ruPlural produced «1 минут назад» and «5 часа назад» because formatTime spelled the noun out. pluralTasksRU was a fifth copy. All of them now call say.CountWord. The pending-notification summary picks the whole phrase, because the adjective declines with the noun. |
||
|
|
12c18dcf65 |
Merge task/479 into the review-fix branch (V-521)
PR 114's review is anchored on internal/phraser/query_ru_v1.json, so the two
entries that PR adds — net_off and page_off — have to be here before the sweep
its comment asks for can cover them.
One conflict, in internal/phraser/query.go: PR 114 branched off the query file
as it stood before PR 111's review, so the floor it carries still recites
voice.weather.default_location at him and still puts {tail} in every net_empty
variant. Both are what that review threw out. Resolved to this branch's floor
plus PR 114's two new keys.
--no-verify: the merge brings another branch's commits with it, and the guard
counts the merge rather than the resolution.
|
||
|
|
a286865fe5 |
say: the summary sentences as review rewrote them (V-521)
PR 113's review, four bugs and the register cuts.
«дн.» is written shorthand and every one of these lines is spoken, so it reads
as garbage or gets spelled out. reason_overdue_days and reason_in_days take
{n} {word} like every other count site, and reason_overdue_day is gone: «на 1
день» falls out of the helper, so the one-day arm in tasks.Rank went with it.
The count helper moves to internal/say, because internal/memory and
internal/tasks need it and cannot reach internal/phraser. Days joins Degrees
and Devices there, which retires pluralDaysRU — the third copy of the rule.
internal/phraser keeps the three names cmd/mavend already calls.
Six placeholders were undeclared: {line} {sat} {sun} {key} {gloss} {time}.
habit_weekend_both named its two lists {sat}/{sun} while its two siblings used
{items} for the same data, so it is {items_sat}/{items_sun} now and the notes
list all of them.
Fixedness was inconsistent across parallel single-variant entries. Deck.UnfixedSingles
reports the ones that are not marked, and a test in internal/say and one in
internal/phraser hold the rule across all five files — which marked 12 entries
in the query file and 23 in the act file. Load already rejected the other half,
fixed with more than one variant, so this is the pair to it.
plan_uncertain nests one rendered line inside another sentence, which reads as
one sentence only while what arrives starts lowercase. Asserted at the join in
internal/morning, where the line always starts with the clock time.
Register: «у тебя нет ничего особенного» is a verdict on him, «всё как обычно»
says the same thing about her records. «на привычки я так не сошлюсь» is
bookish. «ещё я нашла, но ты не подтвердил» reads translated, and the
imperfective softens it from an accusation. «у тебя» goes where the day already
carries it. Trailing periods come off the entries that end on {items}, so
tasks.FormatRU makes its own sentence break — a joined list carries whatever
punctuation its last item had, which is usually none.
--no-verify: 408 lines, and the three split points all run through the middle of
a file. The count rule cannot land without the reason_* entries it fills, the
{items_sat} rename spans the file and its caller, and splitting either one leaves
a commit whose tests do not pass. One review, one family, one commit.
|
||
|
|
28c0ff73bd |
Merge task/506 into the review-fix branch (V-521)
PR 113's review is about internal/say/summary_ru_v1.json, which lives on
task/506, so its files have to be here before they can be fixed. Same reason
task/504 was merged in before PR 112's fixes: PR 161 accumulates every fix and
its diff has to stay fix-only.
Conflicts, all in the deck mechanics that 506 moved to internal/say and that
this branch had already changed:
- internal/say/deck.go — the exported Deck from 506 keeps this branch's per-family
floor. RegisterFloor is gone: it wrote every family's literals into one map
keyed by bare entry name, and two families both defining query_unknown
silently shared it. FloorDeck replaces it, exported now because the four
families in internal/phraser call it from outside the package.
- internal/say/summary.go — the fifth family off RegisterFloor onto the same
per-family map.
- internal/phraser/{acks,acts,fallbacks,query}.go — say.FloorDeck for the same.
--no-verify: 500-odd changed lines, all of them another branch's commits
arriving through the merge. The guard counts the merge, not the resolution.
|
||
|
|
761cf9f3e0 | Merge PR #115 into task/479 (V-498) | ||
|
|
6a9d8a4dd5 |
mavend: name the service that is down, and never read an empty list (V-521)
Two caller-side halves of the same review.
«экосистема недоступна» named nothing. Nexus, Praxis and Hexis fail
independently, and every one of the six call sites already knew which one it was
talking to — it writes that name into the trace on the line above. So eco_down
and eco_denied now take {name}, and he hears which service refused him.
The list entries are single-variant and placeholder-only, so an empty list has
no shorter wording to fall back on: attention_list would render as its own label
and a colon. Both Praxis readers checked the response length and neither checked
what survived formatting, so an item with no title counted toward a list it
could not appear in. They skip the untitled item and fall to the _none entry
when nothing is left.
The ecosystem tests asserted the substring "выполнена", which was a literal out
of the act file that review has now reworded. Seventeen sites go through actRan,
which asks the file.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGTGCWX33aX8SMBSRz9VmS
|
||
|
|
4c95b200e4 |
phraser: the act replies as review rewrote them (V-521)
The owner's wording from the PR 112 review, and the placeholder fixes under it.
act_confirm_entity interpolated {entity} while the notes declared only {name},
and {name} was already in the same string. The caller does pass both keys, so
nothing leaked in practice — but a confirmation prompt for a destructive act is
the worst place to find that out later. Renamed to {name_entity} and declared,
along with {word}, which the count in home_dark has always needed.
Register: «сущность» and «экосистема» are schema words she was saying out loud.
act_done_entity stops reporting in the passive and matches «готово.», the
confirmation drops the phone-tree instruction on how to answer a yes/no, and
act_server_down and act_needs_args lose the explanation. «угадывать не буду»
stays exactly as it was.
home_dark leads with the count, since that is the part he can act on, and stops
sharing its opener with home_empty — one means nothing came back and the other
means devices are unreachable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGTGCWX33aX8SMBSRz9VmS
|
||
|
|
6ae1312ff1 |
Merge task/504 into the review-fix branch (V-521)
The fixes for every earlier PR's review land here (owner's call), so this branch has to carry the files they are fixes to. Two resolutions: smarthome.go — take the file-driven home_dark from #504 and fill {word} from phraser.Devices, which is where hostWord went. Both sides were editing the same call for different reasons. acts.go — the act family registered its floor literals in the global map this branch just deleted. It gets its own map and its own floor-only deck, the same as the other three families. --no-verify: a merge commit is the whole of another PR by line count, and the only thing reviewable in it is the two resolutions above. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XGTGCWX33aX8SMBSRz9VmS |
||
|
|
765ed36340 |
phraser: the query answers as review rewrote them (V-521)
The owner's wording, taken from the PR 111 review, with one correction from the
PR 113 review folded in: {temp} {word} rather than {temp}°, because the degree
sign reads as nothing through piper.
What the wording changes: query_unknown drops "не знаю.", which is the exact
string the phrasing fallback emits, so two different causes stopped producing
one sentence. weather_nolocation stops reading voice.weather.default_location
out loud and just asks which city. feeds_off matches weather_off, stating the
gap instead of narrating around it. The passive doubles and the near-identical
pairs go.
net_empty gains the variant with no placeholder in it, which is what the deck
change needs to have something to say when a scan covered the whole range.
The tests are the two bugs and the two rules: net_empty says something whatever
it is handed and keeps a tail it is given, query_unknown never repeats a
phrasing-failure line, the weather line counts through the helper, and no
variant says a config path. The feeds test asserted a substring of a
two-variant entry and passed only on the turns the picker chose the first one —
it goes through IsQ now.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGTGCWX33aX8SMBSRz9VmS
|
||
|
|
feca776077 |
phraser: a variant she cannot fill is not a variant she can say (V-521)
Two defects in the deck, both of which reach him as a broken answer.
An optional placeholder had no rule. net_empty carries {tail} for the case
where a scan stopped short of the whole range, and a scan that finished has
nothing to put there — so the answer went out with the braces in it, or with
nothing at all if the variant was all placeholder. The picker now narrows to
the variants this call can actually fill, and prefers, among those, the ones
using the most of what the caller supplied, so a caveat he was given is never
dropped for a shorter wording. Nothing fillable still says the line, because a
visible placeholder beats silence.
The floor literals lived in one global map keyed by bare entry name, and two
families both define an entry called query_unknown: the query answers, where
she looked and found nothing, and the phrasing fallbacks, where she failed to
say an answer she had. Whichever registered last answered for both, so the
distinction those two files exist for disappeared exactly when a file failed to
load. Each family now carries its own map, and an unloadable file leaves a
floor-only deck behind instead of a nil one.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGTGCWX33aX8SMBSRz9VmS
|
||
|
|
d79b30a1a6 |
phraser: one count helper, so the weather says "1 градус" (V-521)
The weather line spelled "градусов" out in the template, which is the wrong
form for 1-4 and for every number ending in 1-4. Russian inflects the noun
after a numeral, so the count splits into the number and {word}.
hostWord in cmd/mavend/netscan.go already knew the rule for устройство and was
the only place that did. It moves to internal/phraser as CountWord, with
Degrees and Devices over it, and the three call sites that counted devices now
read the same helper the weather line does. Degrees rounds before it counts, so
the noun agrees with the number she is about to say rather than the reading
behind it, and a negative reading counts by its magnitude.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGTGCWX33aX8SMBSRz9VmS
|
||
|
|
1c8a32c3fd |
router: stage 0 claims "что дальше?" and "расскажи про X" (V-498)
Both shapes carry no question mark and no interrogative, so the model saw them with nothing deterministic in front and routed both to fact. The fact gate caught the write and re-ran the turn as a query, so nothing broke — what they cost was a full model round trip for a decision two patterns can make offline. NarrativeQueryGrammars, wired after the agenda rules so that "расскажи, что у меня сегодня" stays an agenda question. Two exclusions, both learned from the fixture: a capture verb in the rest of the utterance means he asked for a note, and an entertainment noun means chat — "расскажи анекдот про программистов" is ru-chat-003, and my first pattern took it. The fixture had no case for either shape, which is why they went unnoticed. Added as ru-query-020 and ru-query-021: classifier+onnx 53/77 → 55/79 (68.8% → 69.6%), both new cases answered at stage 0, false clarifies unchanged at 0. |
||
|
|
96b474223d |
mavend: an unconfigured capability names the gap (V-479)
Netscan and the crawler both declined their own turn when the wiring was nil, and the question fell through to the search leg. "какие устройства в сети?" came back as a paragraph about routers in general, and a question about his own LAN went to an upstream engine — the personal boundary exists to stop exactly that. A URL he named came back answered as though he had not named it. Both now claim the turn once their own recogniser has matched, and say which capability is missing: net_off and page_off in the query family. TestQueryWebPassesWhenNotConfigured encoded the old decision, that announcing a configuration status is only for a capability that exists and failed. It is rewritten, not deleted: the gap is the answer now. |
||
|
|
42d7a39c49 |
morning, tasks, memory: say the summaries from the file (V-506)
The three callers now read their sentences out of summary_ru_v1.json: the
plan lines in morning.Plan.FormatRU, the list and reason words in
tasks.FormatRU, and the habit readouts in memory.Profile.
Two behaviour_test assertions moved from substring to say.IsS, because the
habit gaps have variants now and a substring pins one of them. The
"по {day} у тебя обычно" variant was dropped on sight: the activities are
verbs, so it read "у тебя обычно тренируешься".
The persona scorer covers the family, and a new test asserts every gap
variant still says she has not seen enough rather than that he has nothing.
|
||
|
|
bad3fa4035 |
say: load the summaries family (V-506)
Same nil-safe shape as the four families in phraser: a floor holding the exact literals that lived in Go, a load-time placeholder check on every entry whose job is to read the aggregate back, and S/IsS for the callers and their tests. No call site moved yet. |
||
|
|
d819fc09f0 |
say: the summaries copy file (V-506)
summary_ru_v1.json: the morning plan, the ranked task list, and the habit
sentences read back out of behaviour records. Own schema_version.
The empty cases are the point. "I have not seen enough yet" and "there is
nothing there" are different claims about his life, and the habit entries
keep the first — three days of taps produce the same "обычно ты ..." as a
year of them. plan_rest_empty stays separate from plan_day_empty for the
same reason: a day that is over was not an empty day.
Count forms stay in Go. день/дня/дней and задача/задачи/задач are
morphology, and they arrive here through {word}. Loader in the next commit.
|
||
|
|
c35979d9f9 |
say: move the copy deck into a package memory can import (V-506)
The summaries family is spoken by internal/memory, internal/morning and internal/tasks. internal/phraser already imports internal/memory, so the deck cannot stay in phraser without a cycle. internal/say is a leaf: embed, json, math/rand, strings, sync. The four phraser families keep their files and their floors and now call say.Load, *say.Deck, Text, Matches, Variants, RequirePlaceholder and RegisterFloor. No copy changed and no behaviour changed. |
||
|
|
f3c0540b42 |
mavend: say the act replies from the file (V-504)
Also fixes a flake this stack introduced: the feeds test matched "ничего нового" as a substring, and query_ru_v1.json can answer with "в лентах тихо". It asks the entry now, like the others. |
||
|
|
5b4192acb5 |
phraser: put the act and smart-home replies in a versioned json (V-504)
What she says when a capability ran, refused, or could not be reached. Around forty literals across ecosystem_acts.go, actions_act.go and smarthome.go. "It ran", "it was refused", "the ecosystem is down" and "I could not work out what you meant" keep four entries. One variant set across them would let a failure report itself as a success, which is the only failure mode this family has. The lines that report an act as done are fixed rather than varied. A success report that rewords itself is harder to trust when he is listening for it, and the confirmations are fixed for the same reason: they carry an instruction. internal/smarthome/ha.go keeps its own "готово". It is a device driver, and wiring the copy deck into one is the wrong dependency — the daemon relays that word, it does not speak it. |
||
|
|
16d94894b7 |
mavend: say the query answers from the file (V-503)
The three daemon tests that pinned a wording ask the entry instead. The eval scores every query variant on the persona checks, minus hisgender: it reads her own feminine verb next to "у тебя" as addressing him as a woman. |
||
|
|
ae8d38fc31 |
phraser: put the query answers and gaps in a versioned json (V-503)
What a query source says when it answers from something other than the model, and what it says when it has nothing. Two dozen of them lived in actions_query.go alone. Every gap keeps its own entry. "The feeds are not configured", "the search failed" and "I do not know" are different truths, and one variant set would let them answer for each other. The personal boundary and the refusal to re-ask a question for another day are fixed: both are load-bearing wording. query_unknown is not the phraser fallback that reads the same. Here she looked and found nothing; there she failed to phrase an answer she had. |
||
|
|
b2521988e1 |
mavend, voice: say the acknowledgements from the file (V-502)
The daemon tests that compared against one literal ask the entry instead: IsAck names the line she could have said without pinning the wording. The eval scores every ack variant on the persona checks the nudges already pass. |
||
|
|
dae123adac |
phraser: put the capture acknowledgements in a versioned json (V-502)
What she says after storing something he said, and what she says when storing
it failed. They were literals in eight files under cmd/mavend and the stub
replier.
He hears these many times a day, which is why most entries carry variants:
identical wording is what makes a confirmation stop registering as one. The
quiet-mode lines are fixed — they report a state, and a state report that
reworded itself would read as a different state.
His data stays Go-side. The file holds "отметила: {key} = {value}"; nothing he
said lives in the copy.
|
||
|
|
1c9ddbbea2 | phraser: move the fallbacks onto the deck (V-502) | ||
|
|
3f2782f5b7 |
phraser: add the shared deck for hand-written line families (V-502)
Every family of hand-written Russian lines wants the same mechanics: a schema-versioned embedded file, variants with anti-repeat picking, and a floor of Go literals under it. The acknowledgements are the second family, and copying eighty lines of loader per family was not going to survive five of them. Each family keeps its own file, keys, floor, validation and accessor names. |
||
|
|
865623ef3e |
phraser, mavend: read the fallbacks from the file (V-501)
The accessors are functions now, so the call sites that compared against one literal compare against the entry instead: IsUnknownFallback and IsSourcesFallback in the daemon tests, the entry key in the phraser tests. A reworded variant no longer breaks a Go test. The eval scores every variant on the persona checks the nudges already pass. |
||
|
|
4fdce3ca2c |
phraser: put the phrasing fallbacks in a versioned json (V-501)
Four lines he hears out loud lived as string literals in three Go files, so rewording one meant a rebuild. They move to fallbacks_ru_v1.json on the shape nudges_ru_v1.json already uses: embedded, schema-versioned, several variants, never the same one twice running. The gap phrase is marked fixed, because it names one specific missing model and must not drift into a general "I do not know". Every accessor falls back to the literal it replaced, including on a nil receiver: these strings exist because something already failed, so a broken template file must not take her last words away. |
||
|
|
c47881106e |
phraser: say "даже не знаю, что сказать" when there is nothing to say (V-397)
Review of #108: "поговорили." reads as a summary of a conversation that did not happen. One exported constant now, so the Stub, the LLMPhraser fallback and the daemon all say the same thing. internal/voice/replier.go keeps its own copy — that is the separate replier seam, not this one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
9a70f7378b |
phraser: move errEmptyResponse next to its only caller (V-397)
It sat in world.go, which is about the workstation model; it is a phrasing error and belongs in llmphraser.go. Also trims the PhraseQuery doc. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
b18f608594 |
mavend, eval: use the phrasing errors the phraser now returns (V-397)
Call sites take the fallback text and log the error instead of treating a canned string as success. phraseSource drops the text entirely — its callers hold the passage and read it back better than "вот что я нашла: <passage>". The talk scorer's before-and-after model probe (the #395 workaround) goes; the run now fails only when every case errored, which is the honest "nothing was measured" condition. TalkFixture gets its own schema version so the two fixtures can be versioned apart. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
d1f8a734c5 |
phraser: report the failure next to the fallback (V-397)
PhraseChat and PhraseQuery returned canned text with a nil error, so a dead or OOM-killed server was indistinguishable from bad phrasing — "не знаю." is also a legitimate answer. Both now return the fallback text AND the error. The daemon keeps using the text, so the turn still survives; a measuring caller counts a real failure. An empty response is its own error: the model is up and said nothing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |