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.
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
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.
The results channel was sized by the number of hosts while each worker
sends once per open port, so a subnet with more open ports than
addresses filled the buffer and blocked a worker forever. Nothing drains
the channel until wg.Wait returns and the sends have no ctx.Done case,
so the calling turn hung for the life of the process. Size it by probes.
Three more claims the scanner could not back. MaxHosts was spent in
order, so the second of two configured subnets got two addresses out of
254 with nothing logged. A run cut short by the cap or the deadline came
back indistinguishable from a complete one, and the shipped defaults
never fit the budget, so every scan was silently truncated at the top of
the range. Scan now reports truncation, targets are taken round-robin,
and the default rate and the budget are consistent with a /24.
The spoken reply read dotted quads out loud on the voice path. It now
says how many devices and what shape, and writes the address list as a
note, which is also the only record that Maven put packets on the LAN.
The network noun is matched whole so posetil is not a scan, the rate has
a stated ceiling, and a repeat question inside two minutes reuses the
answer.
Both query sources claimed the turn when the capability was off, which
let an unconfigured scanner and an unconfigured house swallow questions
that used to reach recall. Both now fall through.
Found in review of #81 and #80.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TrVSBKe3RFDF4fGYKWYQnX
internal/netscan/ discovers hosts on the network Maven is configured to look at:
a TCP-connect scan (net.DialTimeout, no raw sockets, no privileges) plus a read
of the kernel's ARP cache. Wired as a read-only query source, "network", so
"какие устройства в сети?" is answered by a scan instead of by whatever old note
happens to be nearest.
Scanning is a read, but an unbounded scanner on a home LAN is noisy and easy to
point somewhere it should not go, so the package is built around four bounds:
- Scan takes NO target argument. The range comes from the config block and
from nowhere else, so there is no exported way to scan an arbitrary prefix
and nothing an utterance, the router, or a scanned host says can retarget
it. That is asserted directly: the test watches every address handed to the
dialer and fails if one falls outside the configured prefix. The ARP cache —
the one input the network itself populates — is filtered to the configured
range for the same reason.
- Every configured CIDR must be private (RFC1918 / CGNAT / link-local) and no
larger than 1024 addresses. 8.8.8.0/24, 0.0.0.0/0 and 10.0.0.0/8 are refused
at config load, not after the packets have left.
- Rate-limited to a configured connections-per-second across the whole scan,
so it looks like background traffic rather than a portscan.
- Bounded in total by MaxHosts, a per-connection timeout, a 20s turn budget
and the context; a canceled scan stops dialing immediately.
Off unless configured: dark without "enabled": true, and applyDefaults
normalises a disabled block to nil. deploy/mavend.json carries it disabled.
BLUETOOTH IS NOT SHIPPED, AND IS BLOCKED, NOT SKIPPED. The plan's other half
(internal/bluetooth/, RSSI presence probes) needs a bluez stack that is not
here: bluetoothctl and hcitool are not installed, bluetoothd is not installed,
the bluetooth unit is inactive, and org.bluez is not on the system bus. hci0
exists as a kernel device and nothing can talk to it. The docker deploy is
further away still — it would need host networking, the D-Bus system socket
passed in, and CAP_NET_ADMIN. Writing an exec wrapper around a binary that does
not exist, against an output format nothing here can produce, would be a guess
dressed as a feature. It needs a decision about privileging the container before
any of it is worth writing.
Vikunja #257