Skip to content

Commit b52deda

Browse files
chenchaoyiclaude
andauthored
fix(tui): align events vocabulary + filter-keys hint with A1 (#109)
Two A1-era cleanups bundled from the 2026-05-21 EN<->ZH TUI audit: 1. EN event panel said "joined" but the events are `*_seen`. `ble_device_seen` / `bonjour_service_seen` / `lan_host_seen` rendered in EN as `[BLE] device joined:` / `[BJ] service joined:` / `[LAN] host joined:`. ZH already said `设备出现 / 服务出现 / 主机出现` and the JSONL `type` always said `*_seen`. "Joined" also lies about semantics — events fire on the first passive observation, including strangers' phones walking past. Renamed three EN i18n keys to `device seen: ` / `service seen: ` / `host seen: `; ZH unchanged. 2. Events filter docs claimed `1/2/3/4/0` but A1 added `5/6/7`. Bindings 5/6/7 → ble/bonjour/lan are wired in `EventsScreen.BINDINGS`, but four user-facing strings (modal footer + help-modal prose, EN + ZH) still listed only the legacy five keys. Extended to `1/2/3/4/5/6/7/0` in both locales so the new filters are discoverable from the TUI alone. Spec: tui-shell EventsPanel-format requirement MODIFIED — three bullets + one scenario example flip from `joined` to `seen` and note why the verb matters. Tests: 3 string-assertion flips in test_tui_helpers.py (device/service/host joined -> seen). 768 pytest passed, snapshot regression green, both openspec validates clean. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent b1383ae commit b52deda

9 files changed

Lines changed: 279 additions & 21 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ behaviours between releases.
1212
## [Unreleased]
1313

1414
### Fixed
15+
- **Events panel said "joined" but the events are `*_seen`.** EN UI rendered `ble_device_seen` / `bonjour_service_seen` / `lan_host_seen` as `[BLE] device joined:` / `[BJ] service joined:` / `[LAN] host joined:`. ZH already said `设备出现 / 服务出现 / 主机出现` (appeared / seen). The JSONL `type` field always said `*_seen`. The EN wording also lied about semantics — "joined" reads like *paired / associated*, but the event fires on the first passive observation, including strangers' phones walking past. Renamed three EN i18n keys to `device seen: ` / `service seen: ` / `host seen: `; ZH unchanged.
16+
- **Events filter footer claimed `1/2/3/4/0`; A1 added `5/6/7`.** The EventsScreen filter cycle has eight buckets since A1 (`ble` / `bonjour` / `lan` on keys `5` / `6` / `7`), the bindings work, but four user-facing strings — events-modal footer and help-modal "Events modal (m)" paragraph, EN + ZH — still listed only the legacy five keys. Extended to `1/2/3/4/5/6/7/0` in both locales so the new filters are discoverable from the TUI alone.
1517
- **BLE `ble_device_left` re-emission bug.** A device at the edge of range whose adverts the macOS Bluetooth stack briefly stopped delivering would TTL-evict, re-populate `_devices` from the next advert, evict again, and re-emit `BLEDeviceLeftEvent` on every cycle. One identifier in a real 5.6 h capture produced 229 left events from a single seen — 67,548 BLE events / 13 MB JSONL for the session. `BLEPoller._detect_transitions` now gates left-emission on a per-session `_departed_identifiers` set: at most one left per seen, identifier silent for the rest of the session after departure. JSONL size for the captured session drops ~63%.
1618

1719
## [1.4.0] — 2026-05-21

docs/zh/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
## [Unreleased]
1212

1313
### 修复
14+
- **事件面板英文写「joined」、但事件其实是 `*_seen`** EN UI 把 `ble_device_seen` / `bonjour_service_seen` / `lan_host_seen` 渲染成 `[BLE] device joined:` / `[BJ] service joined:` / `[LAN] host joined:`,但 ZH 一直是 `设备出现 / 服务出现 / 主机出现`,JSONL `type` 字段一直是 `*_seen`。"joined" 还会让人误以为「配对 / 关联」—— 实际事件触发的是首次被动观察到,包括路过的陌生人手机。把三个 EN i18n key 改为 `device seen: ` / `service seen: ` / `host seen: `;ZH 不变。
15+
- **事件过滤页脚仍写 `1/2/3/4/0`,A1 早就加了 `5/6/7`** EventsScreen 过滤循环自 A1 起已经是八桶(`ble` / `bonjour` / `lan` 绑定到 `5` / `6` / `7`),按键也接好了,但事件弹窗页脚 + 帮助弹窗里的「Events modal (m)」段落(EN + ZH 共四处)还在只列旧的五个键。统一改为 `1/2/3/4/5/6/7/0`,让新加的过滤桶在 TUI 里就能被发现。
1416
- **BLE `ble_device_left` 重复发送的 bug。** 范围边缘的设备如果广播被 macOS 蓝牙栈短暂卡掉一次,会触发 TTL 失效;紧接着下一条广播又把 `_devices` 填回去、再失效、再发 `BLEDeviceLeftEvent`,循环不止。真实 5.6 小时抓取里有一个 identifier 从单个 seen 派生了 **229** 个 left 事件,整个会话产出 67,548 个 BLE 事件 / 13 MB JSONL。`BLEPoller._detect_transitions` 现在用会话级 `_departed_identifiers` 集合给 left-emission 加门:一个 seen 最多对应一个 left,发完之后该 identifier 本会话内静音。该抓取的 JSONL 体积下降约 63%。
1517

1618
## [1.4.0] — 2026-05-21
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# design — align-events-vocabulary
2+
3+
## Why bundle the two findings
4+
5+
Both findings are A1-era cleanup: the seen-side EN wording and
6+
the filter-keys hint both got written when the cycle had five
7+
buckets, before the three new transition event types were added.
8+
They touch the same `i18n.py` / `tui.py` files and the same
9+
spec section. Shipping them in one PR avoids a second
10+
re-translation cycle for a one-string change.
11+
12+
## i18n key rename, not value-only edit
13+
14+
The catalog entries are `"device joined: "``"设备出现:"`. The
15+
ZH value is already correct. So the change is on the EN side —
16+
the catalog key (which is also the EN-rendered string in
17+
diting's i18n model).
18+
19+
The clean way to do this:
20+
21+
```python
22+
# i18n.py — was
23+
"device joined: ": "设备出现:",
24+
"service joined: ": "服务出现:",
25+
"host joined: ": "主机出现:",
26+
27+
# becomes
28+
"device seen: ": "设备出现:",
29+
"service seen: ": "服务出现:",
30+
"host seen: ": "主机出现:",
31+
```
32+
33+
Call sites at `tui.py:1947, 1970, 1993` flip from
34+
`t("device joined: ")``t("device seen: ")` etc.
35+
36+
If any old build reads a JSONL log produced by a new build,
37+
the analyzer is locale-stable English keys (`ble_device_seen`)
38+
— the renamed UI string never enters the log. No back-compat
39+
concern there.
40+
41+
## Filter-keys hint wording
42+
43+
Current: `Press 1/2/3/4/0 to filter; m or Esc to close`.
44+
45+
Three options for the extended form:
46+
47+
1. **Explicit:** `Press 1/2/3/4/5/6/7/0 to filter; m or Esc to close`
48+
2. **Range:** `Press 1–7 to filter, 0 to clear; m or Esc to close`
49+
3. **Implicit:** `Press 1–7/0 to filter; m or Esc to close`
50+
51+
(1) is the obvious extension and what the audit recommended.
52+
(2) and (3) are more compact, but `1–7` is less mechanically
53+
discoverable than the keys-as-digits list — a user scanning the
54+
footer for which key sets `lan` does not learn that 7 is the
55+
answer without trying. (1) wins on user discoverability.
56+
57+
Same expansion applies to the help-modal prose at
58+
`tui.py:612` / `i18n.py:880, 886`. ZH counterpart at
59+
`i18n.py:1249` likewise.
60+
61+
## What the spec MUST change
62+
63+
`openspec/specs/tui-shell/spec.md:135-147` lists the seven A1
64+
types' rendered formats with `device joined` / `service joined`
65+
/ `host joined`. Three bullets and one scenario example flip
66+
to `seen`. Everything else in the requirement stays.
67+
68+
The filter-cycle requirement at `spec.md:96-117` is already
69+
correct (it lists the eight buckets and the scenarios). The
70+
audit-finding is about the prose hint, not the spec — no spec
71+
change needed for finding #2.
72+
73+
## Test changes
74+
75+
Three string-only flips in `test_tui_helpers.py`:
76+
77+
- `:2659` `assert "device joined" in text``assert "device seen" in text`
78+
- `:2692` `assert "service joined" in text``assert "service seen" in text`
79+
- `:2725` `assert "host joined" in text``assert "host seen" in text`
80+
81+
No new tests needed for the i18n side — the existing tests
82+
exercise the formatter end-to-end.
83+
84+
For finding #2, the audit recommends no new test — the prose
85+
itself is review-enforced (per TESTING.md row 362 for EN, 353
86+
for ZH: "HelpScreen content review-enforced"). Adding a
87+
string-pinning test would couple the test to specific phrasing
88+
that may drift later; not worth the maintenance cost.
89+
90+
## What this change does NOT touch
91+
92+
- The JSONL `type` field. Already locale-stable English.
93+
- The `tui-shell` filter-cycle requirement (unchanged — only
94+
the prose-hint is stale, not the spec).
95+
- The `events` capability spec. Untouched.
96+
- The analyzer or any cross-session aggregation. Unaffected.
97+
- ZH catalog values. Already correct.
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# align-events-vocabulary
2+
3+
## Why
4+
5+
A TUI audit on 2026-05-21 with `DITING_LANG=en` and
6+
`DITING_LANG=zh` flagged two A1-era post-ship issues:
7+
8+
**1. EN UI says "joined" but the event is `*_seen`.** Every
9+
`ble_device_seen` / `bonjour_service_seen` / `lan_host_seen`
10+
event renders in EN as `device joined: ` / `service joined: ` /
11+
`host joined: `. ZH translates the same EN keys to `设备出现:`
12+
/ `服务出现:` / `主机出现:` — i.e. "appeared / seen". The
13+
JSONL `type` field, the BLEPoller's internal vocabulary, the
14+
spec's MODIFIED requirement landed in fix-ble-left-dedup all
15+
say "seen". "Joined" reads like *paired / associated* — but
16+
the event fires on the first passive observation, including
17+
random strangers' phones walking past. The EN wording is
18+
misleading and disagrees with ZH and the JSONL schema. EN and
19+
ZH agree on the sibling `*_left` events (`device left` /
20+
`设备消失`), so only the seen-side has drifted.
21+
22+
**2. Events-filter docs claim 1/2/3/4/0; A1 added 5/6/7.**
23+
The EventsScreen filter cycle has eight buckets since A1 —
24+
`tui.py:782-784` binds `5` / `6` / `7` to `ble` / `bonjour` /
25+
`lan` and `action_set_filter` accepts them. The bindings work.
26+
But four user-facing strings still say "1/2/3/4/0":
27+
28+
- `src/diting/tui.py:884` — events-modal footer hint
29+
- `src/diting/i18n.py:1248-1249` — that footer's ZH value
30+
- `src/diting/tui.py:612` — help-modal "Events modal (m)" paragraph
31+
- `src/diting/i18n.py:880, 886` — the help-modal paragraph EN + ZH
32+
33+
The new BLE / Bonjour / LAN filters are undiscoverable without
34+
reading the source. (The HelpScreen test
35+
`test_events_screen_filter_cycle_has_eight_buckets` asserts the
36+
filter-bucket cycle has eight entries, but not that the key-list
37+
in the prose matches.)
38+
39+
## What changes
40+
41+
- Rename three EN i18n catalog keys to match the canonical event
42+
vocabulary: `device joined: ``device seen: `,
43+
`service joined: ``service seen: `, `host joined: `
44+
`host seen: `. ZH values are unchanged (`设备出现` etc. already
45+
mean "appeared / seen").
46+
- Update the call sites in `tui.py:1947`, `:1970`, `:1993`.
47+
- Extend the four "1/2/3/4/0" strings to "1/2/3/4/5/6/7/0" (or
48+
a more compact phrasing — see design.md).
49+
- Update the `tui-shell` spec: the EventsPanel format bullets
50+
for the seven A1-added types switch from `joined` to `seen`,
51+
and the scenario example matches.
52+
- Update three existing tests in `test_tui_helpers.py` that
53+
assert the old wording.
54+
55+
## Impact
56+
57+
- **EN UI** — three lines in the events panel and one events-modal
58+
footer hint change wording. No layout / width change.
59+
- **JSONL log** — untouched; the canonical event type names
60+
(`ble_device_seen` etc.) are already correct and remain
61+
load-bearing identifiers.
62+
- **ZH UI** — no change. ZH already used "出现" / "appeared / seen"
63+
for the seen events.
64+
- **Spec**`tui-shell` MODIFIED requirement around EventsPanel
65+
formatting. No new requirement, no removed requirement.
66+
- **Tests** — three string-assertion flips. No semantic change.
67+
68+
## Affected code
69+
70+
- `src/diting/i18n.py` — three i18n keys + filter-footer hints
71+
- `src/diting/tui.py:612, 884, 1947, 1970, 1993`
72+
- `tests/test_tui_helpers.py:2659, 2692, 2725`
73+
- `openspec/specs/tui-shell/spec.md:135-147` (delta target)
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
## MODIFIED Requirements
2+
3+
### Requirement: EventsPanel SHALL format the twelve event types with type-prefix tags
4+
`EventsPanel.append_event` SHALL render each event with a leading bracket-tag identifying its type, followed by a short type-specific summary. The full tag set is:
5+
6+
| Tag | Event type(s) |
7+
|---|---|
8+
| `[ROAM]` | `roam` |
9+
| `[STIR]` | `rf_stir` |
10+
| `[LATENCY]` | `latency_spike` |
11+
| `[LOSS]` | `loss_burst` |
12+
| `[LINK]` | `link_state` |
13+
| `[BLE]` | `ble_device_seen` / `ble_device_left` (NEW) |
14+
| `[BJ]` | `bonjour_service_seen` / `bonjour_service_left` (NEW) |
15+
| `[LAN]` | `lan_host_seen` / `lan_host_left` / `lan_host_dhcp_rotation` (NEW) |
16+
17+
The seven new event types' rendered formats:
18+
19+
- `[BLE] device seen: <vendor> · <name>` (or `(unknown)` / `(anonymous)` when blank)
20+
- `[BLE] device left: <vendor> · <name> · <duration>`
21+
- `[BJ] service seen: <category> · <host>` (or `(unknown)` when category blank)
22+
- `[BJ] service left: <category> · <host> · <duration>`
23+
- `[LAN] host seen: <vendor> · <name-or-ip>` (`name` = bonjour_name OR hostname OR IP)
24+
- `[LAN] host left: <vendor> · <name-or-ip> · <duration>`
25+
- `[LAN] <vendor> · <name-or-ip> moved <previous_ip> → <new_ip>`
26+
27+
The verb "seen" — not "joined" — matches the canonical event type names (`ble_device_seen`, `bonjour_service_seen`, `lan_host_seen`) and the ZH translation (`出现` ≈ "appeared / seen"). These events fire on passive first observation (strangers' phones walking past, mDNS announces on the link, ARP cache entries appearing), NOT on a deliberate user-initiated association.
28+
29+
Each rendered line SHALL be at most one terminal row even on narrow widths; rendering SHALL use `fit_cells` for the long-name segment.
30+
31+
#### Scenario: BLE seen line
32+
- **WHEN** a `BLEDeviceSeenEvent` with `name="Magic Keyboard"`, `vendor="Apple, Inc."` flows through `append_event`
33+
- **THEN** the EventsPanel surfaces a line `[BLE] device seen: Apple, Inc. · Magic Keyboard`
34+
35+
#### Scenario: LAN DHCP rotation line
36+
- **WHEN** a `LANHostDHCPRotationEvent` with `mac="de:ad:be:ef:00:01"`, `vendor="Apple, Inc."`, `bonjour_name="ccy-MBP24-M4-Office"`, `previous_ip="192.168.1.42"`, `new_ip="192.168.1.77"` flows through `append_event`
37+
- **THEN** the line is `[LAN] Apple, Inc. · ccy-MBP24-M4-Office moved 192.168.1.42 → 192.168.1.77`
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# tasks — align-events-vocabulary
2+
3+
## 1. Spec
4+
5+
- [x] Draft proposal, design, tasks
6+
- [x] Spec delta in `specs/tui-shell/spec.md`
7+
(MODIFIED requirement: EventsPanel format bullets + scenario example
8+
flip from `joined``seen`)
9+
10+
## 2. Implementation
11+
12+
- [x] `src/diting/i18n.py:1199-1204` — rename three EN keys:
13+
`device joined: ``device seen: `,
14+
`service joined: ``service seen: `,
15+
`host joined: ``host seen: `
16+
- [x] `src/diting/tui.py:1948, 1971, 1994` — update `t(...)` call sites
17+
- [x] `src/diting/tui.py:885` — extend events-modal footer:
18+
`Press 1/2/3/4/0 to filter``Press 1/2/3/4/5/6/7/0 to filter`
19+
- [x] `src/diting/i18n.py:1248-1249` — ZH translation of the footer
20+
- [x] `src/diting/tui.py:612` — help-modal "Events modal (m)" paragraph
21+
- [x] `src/diting/i18n.py:880, 886` — that paragraph EN + ZH
22+
23+
## 3. Tests
24+
25+
- [x] `tests/test_tui_helpers.py:2659``"device joined"``"device seen"`
26+
- [x] `tests/test_tui_helpers.py:2692``"service joined"``"service seen"`
27+
- [x] `tests/test_tui_helpers.py:2725``"host joined"``"host seen"`
28+
29+
## 4. Validation
30+
31+
- [x] `uv run pytest` — 768 passed
32+
- [x] `uv run python scripts/tui_snapshot.py --mode regression` — green
33+
- [x] `openspec validate --specs --strict` — 21/21
34+
- [x] `openspec validate align-events-vocabulary --strict` — valid
35+
36+
## 5. CHANGELOG
37+
38+
- [ ] `CHANGELOG.md``## [Unreleased]``### Fixed`
39+
- [ ] `docs/zh/CHANGELOG.md` — mirror EN entry
40+
41+
## 6. Merge + archive
42+
43+
- [ ] PR open, reviewed, merged
44+
- [ ] `/opsx:archive align-events-vocabulary`

src/diting/i18n.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -877,14 +877,16 @@ def fit_cells(text: str, target: int) -> str:
877877
" Filterable scroll of every event the dashboard has detected:\n"
878878
" ROAM (AP switches), STIR (RF disturbance from σ baseline),\n"
879879
" LATENCY / LOSS (link probe spikes), LINK (associate /\n"
880-
" disassociate). Use 1/2/3/4/0 to filter by category. Below\n"
881-
" the list: a per-AP σ table summarising which APs are stable\n"
882-
" vs stirring, plus a σ sparkline covering the trailing hour.\n":
880+
" disassociate), plus BLE / BJ / LAN seen-and-left transitions.\n"
881+
" Use 1/2/3/4/5/6/7/0 to filter by category. Below the list: a\n"
882+
" per-AP σ table summarising which APs are stable vs stirring,\n"
883+
" plus a σ sparkline covering the trailing hour.\n":
883884
" 仪表盘检测到的所有事件可过滤滚动列表:\n"
884885
" ROAM(AP 切换)、STIR(基于 σ 基线的 RF 扰动)、\n"
885-
" LATENCY / LOSS(链路探测尖峰)、LINK(关联 / 断开)。\n"
886-
" 按 1/2/3/4/0 切换过滤。列表下方:各 AP σ 表,标出哪些 AP\n"
887-
" 稳定 / 哪些抖动,以及最近一小时 σ 走势图。\n",
886+
" LATENCY / LOSS(链路探测尖峰)、LINK(关联 / 断开),\n"
887+
" 以及 BLE / BJ / LAN 的出现与消失。按 1/2/3/4/5/6/7/0\n"
888+
" 切换过滤。列表下方:各 AP σ 表,标出哪些 AP 稳定 / 哪些\n"
889+
" 抖动,以及最近一小时 σ 走势图。\n",
888890
" Toggle with n. Two sections: Connected (system-paired\n"
889891
" peripherals you're actively using — keyboards, AirPods, Magic\n"
890892
" Trackpad) and Advertising (everything broadcasting nearby).\n"
@@ -1196,11 +1198,11 @@ def fit_cells(text: str, target: int) -> str:
11961198
"[BLE]": "[BLE]",
11971199
"[BJ]": "[BJ]",
11981200
"[LAN]": "[LAN]",
1199-
"device joined: ": "设备出现:",
1201+
"device seen: ": "设备出现:",
12001202
"device left: ": "设备消失:",
1201-
"service joined: ": "服务出现:",
1203+
"service seen: ": "服务出现:",
12021204
"service left: ": "服务消失:",
1203-
"host joined: ": "主机出现:",
1205+
"host seen: ": "主机出现:",
12041206
"host left: ": "主机消失:",
12051207
" moved ": " 换地址 ",
12061208
"(anonymous)": "(匿名)",
@@ -1245,8 +1247,8 @@ def fit_cells(text: str, target: int) -> str:
12451247
"data ~{n}m": "数据 ~{n}m",
12461248
"(σ history outside the last hour)":
12471249
"(无最近一小时内的 σ 历史)",
1248-
"Press 1/2/3/4/0 to filter; m or Esc to close":
1249-
"按 1/2/3/4/0 切换过滤;m 或 Esc 关闭",
1250+
"Press 1/2/3/4/5/6/7/0 to filter; m or Esc to close":
1251+
"按 1/2/3/4/5/6/7/0 切换过滤;m 或 Esc 关闭",
12501252

12511253
# ---- Calibration CLI ----
12521254
"Calibrating environment baseline ({n}s remaining)...":

src/diting/tui.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -609,9 +609,10 @@ def line(label: str, desc: str) -> None:
609609
" Filterable scroll of every event the dashboard has detected:\n"
610610
" ROAM (AP switches), STIR (RF disturbance from σ baseline),\n"
611611
" LATENCY / LOSS (link probe spikes), LINK (associate /\n"
612-
" disassociate). Use 1/2/3/4/0 to filter by category. Below\n"
613-
" the list: a per-AP σ table summarising which APs are stable\n"
614-
" vs stirring, plus a σ sparkline covering the trailing hour.\n"
612+
" disassociate), plus BLE / BJ / LAN seen-and-left transitions.\n"
613+
" Use 1/2/3/4/5/6/7/0 to filter by category. Below the list: a\n"
614+
" per-AP σ table summarising which APs are stable vs stirring,\n"
615+
" plus a σ sparkline covering the trailing hour.\n"
615616
))
616617

617618
section(t("BLE view"))
@@ -881,7 +882,7 @@ def _render_body(self) -> Group:
881882

882883
def _render_footer(self) -> Text:
883884
line = Text()
884-
line.append(t("Press 1/2/3/4/0 to filter; m or Esc to close"),
885+
line.append(t("Press 1/2/3/4/5/6/7/0 to filter; m or Esc to close"),
885886
style="dim italic")
886887
return line
887888

@@ -1944,7 +1945,7 @@ def _format_ble_device_seen_event(event: BLEDeviceSeenEvent) -> Text:
19441945
line = Text()
19451946
line.append(f"{_ev_ts(event)} ", style="dim")
19461947
line.append(t("[BLE]") + " ", style="bold blue")
1947-
line.append(t("device joined: "), style="white")
1948+
line.append(t("device seen: "), style="white")
19481949
vendor = event.vendor or t("(unknown)")
19491950
name = event.name or t("(anonymous)")
19501951
line.append(f"{vendor} · {name}", style="white")
@@ -1967,7 +1968,7 @@ def _format_bonjour_service_seen_event(event: BonjourServiceSeenEvent) -> Text:
19671968
line = Text()
19681969
line.append(f"{_ev_ts(event)} ", style="dim")
19691970
line.append(t("[BJ]") + " ", style="bold green")
1970-
line.append(t("service joined: "), style="white")
1971+
line.append(t("service seen: "), style="white")
19711972
cat = event.category or t("(unknown)")
19721973
host = event.host or t("(anonymous)")
19731974
line.append(f"{cat} · {host}", style="white")
@@ -1990,7 +1991,7 @@ def _format_lan_host_seen_event(event: LANHostSeenEvent) -> Text:
19901991
line = Text()
19911992
line.append(f"{_ev_ts(event)} ", style="dim")
19921993
line.append(t("[LAN]") + " ", style="bold cyan")
1993-
line.append(t("host joined: "), style="white")
1994+
line.append(t("host seen: "), style="white")
19941995
vendor = event.vendor or (
19951996
t("(random MAC)") if event.is_randomised_mac else t("(unknown)")
19961997
)

0 commit comments

Comments
 (0)