A repeater setting its firmware lacks reads n/a, not ?
v1.15 matches get keys by prefix, so a key it lacks falls into a shorter sibling's branch: get radio.fem.rxgain answers with the get radio line, and gps on a board without its receiver answers "Can't find GPS". Neither is an error string and neither parses, and an unparseable reply left the cache alone, so those rows stayed on ?, which says never asked. Any reply that can't be the setting's value now marks it n/a; only no reply keeps ?. The fold itself rode along in 564ac0e; this adds the regression test, the catalog's note on prefix-shadowed replies, and reflows a docstring line. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
564ac0e6ac
commit
74eabff25f
3 files changed
+24
-3
No files matched your search
@@ -30,8 +30,10 @@ three of its shapes only make sense against that source:
|
||||
Replies are parsed *loosely* on purpose: repeater firmware answers tersely and has changed
|
||||
its phrasing across versions (``"> 20"``, ``"tx: 20"``, ``"OK - repeat is now ON"``), so
|
||||
values are extracted rather than pattern-matched. Firmware without a given key answers
|
||||
with an error string (``??: key`` to a ``get``, ``unknown config: …`` to a ``set``), which
|
||||
the screen records as *this node doesn't have it* rather than breaking.
|
||||
with an error string (``??: key`` to a ``get``, ``unknown config: …`` to a ``set``) — or,
|
||||
because ``get`` matches keys by prefix, with a shorter sibling's value (v1.15 answers
|
||||
``get radio.fem.rxgain`` with the ``get radio`` line). The screen records either as *this
|
||||
node doesn't have it* rather than breaking.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -433,7 +433,8 @@ def _value_text(spec: RemoteSetting, cache: dict, pending: dict[str, str]) -> Te
|
||||
|
||||
Four states, each its own word: the value; ``empty`` for a string the node holds blank;
|
||||
``n/a`` when the node answered with something that can't be this setting's value — its
|
||||
firmware has no such setting; ``?`` when it was never read (or never answered). No age: the lane is the value, and a stamp beside it only crowded it.
|
||||
firmware has no such setting; ``?`` when it was never read (or never answered). No age:
|
||||
the lane is the value, and a stamp beside it only crowded it.
|
||||
"""
|
||||
cached = cache.get(spec.key)
|
||||
if not spec.readable:
|
||||
|
||||
@@ -498,6 +498,24 @@ async def test_read_one_setting_sends_one_read(tui_ctx, admin_device) -> None:
|
||||
assert tui_ctx.remote_store.settings(NODE)["cr"].value == "5" # the same answer filled it
|
||||
|
||||
|
||||
def test_a_reply_that_cannot_be_the_value_reads_n_a(tui_ctx) -> None:
|
||||
"""A node answering a key it lacks with anything but its value reads ``n/a``, not ``?``.
|
||||
|
||||
Regression: v1.15 matches ``get`` keys by prefix, so ``get radio.fem.rxgain`` came back
|
||||
as the ``get radio`` line. It parsed as nothing, and the row stayed ``?`` — never asked.
|
||||
"""
|
||||
replies = {
|
||||
"radio.fem.rxgain": "> 910.525,62.5,7,5", # a shorter sibling's branch answered
|
||||
"gps": "Can't find GPS",
|
||||
"bridge.delay": "??: bridge.delay",
|
||||
}
|
||||
for key, reply in replies.items():
|
||||
assert repeater_admin.remember_reply(tui_ctx, NODE, [get_setting(key)], reply) == 0
|
||||
cache = tui_ctx.remote_store.settings(NODE)
|
||||
for key in replies:
|
||||
assert repeater_admin._value_text(get_setting(key), cache, {}).plain == "n/a"
|
||||
|
||||
|
||||
async def test_apply_reads_the_radio_first_then_sends_one_line(tui_ctx, admin_device) -> None:
|
||||
"""A radio field staged unread restates its siblings from a fresh read, never a guess."""
|
||||
ctx = tui_ctx
|
||||
|
||||
Reference in new issue
Block a user