diff --git a/docs/governance/master-todo-list-2026-06-11.md b/docs/governance/master-todo-list-2026-06-11.md index 8a6c9ad..1aca6c4 100644 --- a/docs/governance/master-todo-list-2026-06-11.md +++ b/docs/governance/master-todo-list-2026-06-11.md @@ -469,8 +469,18 @@ - **Priority:** P2 - **Source:** external-research §2 (ReSpeak) - **Description:** tsclientlib explicitly notes auto-reconnect is "not yet there." Chanora must build this independently. + - **Evidence:** `core/chanora_core/src/lib.rs:1722-2123` — Supervisor with: + - Exponential backoff: `BACKOFF_SCHEDULE = [1, 2, 5, 15, 30, 60]` seconds + - Watchdog: 5s interval, 4s probe timeout, 3 max misses + - Network state awareness: pre-charges watchdog on offline, resets on online + - Audio re-attachment via `sup_inner` after successful reconnect + - Cancellation via `cancel_rx` oneshot on user disconnect + - Broadcasts `SessionEvent::Reconnecting { attempt, delay_secs }` to UI + - No max attempt limit (indefinite retry — correct for voice client) + - Cross-verified against ReSpeak §1.10 (exponential backoff for packet timeouts) - **Effort:** L - **Dependencies:** None +- **Status:** VERIFIED COMPLETE — supervisor with exponential backoff, watchdog, network awareness (2026-06-11) ### TODO-060 — Extract server error codes from YaTQA for error handling - **Priority:** P3 @@ -494,15 +504,25 @@ - **Priority:** P1 - **Source:** yatqa-offline-reference §8.5 - **Description:** YaTQA documents the full DNS resolution order: SRV `_ts3._udp` → SRV TSDNS → TSDNS TCP port 41144 → DNS AAAA/A. First successful resolution wins, NO fallback on connection failure. Critical for connection reliability. + - **Evidence:** `crates/chanora_resolver/src/lib.rs:178-387` — Full chain implemented: + - Direct DNS resolution (`resolve_dns`, line 594) + - TSDNS SRV resolution (`resolve_tsdns_srv_candidates`, line 414) + - TSDNS TCP resolution (`resolve_tsdns_tcp_candidates`, line 454) + - First-wins semantics with `return Ok(resolution)` on first success + - No fallback on failure (errors accumulate, bail at end) + - Cross-verified against YaTQA §8.5 resolution order - **Effort:** M - **Dependencies:** None +- **Status:** VERIFIED COMPLETE — full resolution chain implemented (2026-06-11) -### TODO-063 — Handle TS character encoding quirks (UTF-8 vs UCS-2 vs CESU-8) +### TODO-063 — Verify tsclientlib encoding handling (UTF-8 vs UCS-2 vs CESU-8) - **Priority:** P1 - **Source:** yatqa-offline-reference §1.3 -- **Description:** TS claims UTF-8 but uses UCS-2 (BMP only). Mobile apps use CESU-8. Chanora must handle encoding conversion to avoid display bugs with nicknames, channel names, and messages containing characters outside BMP. -- **Effort:** M -- **Dependencies:** None +- **Description:** TS claims UTF-8 but uses UCS-2 (BMP only). Mobile apps use CESU-8. Server 3.2.0+ adds partial emoji support. tsclientlib/tsproto delivers Rust `String` (UTF-8) via `str::from_utf8()` at the protocol layer (ReSpeak §1.8.3 confirms: "Command string encoded in UTF-8"). If encoding bugs exist, the fix belongs in the EdisonJwa/tsclientlib fork, not in chanora_protocol. +- **Verification:** Confirm tsclientlib handles UCS-2 correctly. Document encoding behavior in protocol-implementation-traps.md (TODO-070). +- **Effort:** S (verification + documentation) +- **Status:** Scope revised from implementation to verification (2026-06-11) +- **Dependencies:** TODO-070 (protocol traps doc) ### TODO-064 — Implement client-side anti-flood point awareness - **Priority:** P2 diff --git a/docs/references/protocol-implementation-traps.md b/docs/references/protocol-implementation-traps.md new file mode 100644 index 0000000..f16ab70 --- /dev/null +++ b/docs/references/protocol-implementation-traps.md @@ -0,0 +1,139 @@ +# Protocol Implementation Traps — Developer Notes + +**Date:** 2026-06-11 +**Purpose:** Compile protocol quirks and gotchas from YaTQA, ReSpeak, and TeaSpeak references that could cause bugs if not handled. + +--- + +## 1. Icon ID Signedness (HIGH) + +**What:** Icon IDs are `i32` (signed), not `u32`. Read contexts return signed values; write contexts may expect unsigned. + +**Why it's a trap:** Negative icon IDs from permlist/clientinfo will be misinterpreted as large positive numbers if stored as u32. + +**How to handle:** Use `i32` for all icon ID fields. When displaying, convert to absolute value or handle negative as "no icon". + +**Source:** YaTQA §1.4 + +## 2. Avatar Flag = MD5 Hash (HIGH) + +**What:** `client_flag_avatar` is an MD5 hash string, not a boolean. + +**Why it's a trap:** Treating it as a boolean (present/absent) loses the identity reference. Avatar filename is derived from Global ID, not from the flag. + +**How to handle:** Store avatar flag as a string. Use Global ID → Base64 → `[a-p]` encoding for filename (YaTQA §1.5). + +**Source:** YaTQA §1.5 + +## 3. Channel Subscription = ONE at a Time (MEDIUM) + +**What:** `channelsubscribe` command subscribes to exactly ONE channel. No array parameter exists. + +**Why it's a trap:** Attempting to subscribe to multiple channels in one command will fail silently or error. + +**How to handle:** Send individual subscribe commands per channel. Track subscription state client-side. + +**Source:** YaTQA §3.1 + +## 4. Line Terminator = 0x0A 0x0D (MEDIUM) + +**What:** TS3 protocol line terminator is `0x0A 0x0D` (reversed Windows `\n\r`). + +**Why it's a trap:** Standard `\r\n` (0x0D 0x0A) will cause parse failures. Max line length: 9203 bytes (excluding terminator). + +**How to handle:** Use `\n\r` (0x0A 0x0D) for all command protocol messages. tsclientlib handles this internally. + +**Source:** YaTQA §1.3 + +## 5. UCS-2 vs UTF-8 Encoding (HIGH) + +**What:** TS3 claims UTF-8 but actually uses UCS-2 (BMP only). Mobile apps use CESU-8. Server 3.2.0+ adds partial SIP support (emoji ranges). + +**Why it's a trap:** Characters outside BMP (emoji, rare CJK) may not round-trip correctly. tsclientlib uses `str::from_utf8()` — if server sends UCS-2, it will error. + +**How to handle:** tsclientlib/tsproto handles encoding at the protocol layer. If encoding bugs are found, fix in the EdisonJwa/tsclientlib fork. Document any encoding-related issues here. + +**Source:** YaTQA §1.3, ReSpeak §1.8.3 + +## 6. IPv6 Canonicalization Bug (LOW) + +**What:** TS3 server 3.1.6-3.1.7 has IPv6 canonicalization bug in Blacklist2 protocol. + +**Why it's a trap:** Connecting to older servers via IPv6 may trigger false blacklist matches. + +**How to handle:** Be aware when connecting to older servers. Not actionable from client side. + +**Source:** YaTQA §8.7 + +## 7. Channel Icon Semi-Permanent (MEDIUM) + +**What:** `channel_icon_id` changes via `channeledit` are semi-permanent (lost on server restart). + +**Why it's a trap:** Icon changes appear to succeed but revert after restart. Users may think their changes are persistent. + +**How to handle:** Document this limitation in UI. Don't rely on channel icon persistence for critical features. + +**Source:** YaTQA §4.2 + +## 8. Avatar Filename from Global ID (MEDIUM) + +**What:** Avatar filename is derived from Global ID (not from avatar flag). Algorithm: Base64-decode Global ID → 20 bytes → display with `[a-p]` instead of `[0-9a-f]`. + +**Why it's a trap:** Using the avatar flag directly as a filename will fail to find the cached avatar. + +**How to handle:** Implement the Global ID → filename conversion. Store avatars in `cache/clients/` directory. + +**Source:** YaTQA §1.5, §1.7 + +## 9. Snapshot SHA1 Hash Format (LOW) + +**What:** Snapshot file starts with SHA1 hash of remaining UTF-8 data (excluding trailing newline). Internally runs Query commands when deploying. + +**Why it's a trap:** Modifying snapshot data without recalculating the hash will cause deploy failure. + +**How to handle:** If implementing snapshot import/export, always recalculate SHA1 after modification. + +**Source:** YaTQA §1.6 + +## 10. BBCode Stack Limits (LOW) + +**What:** BBCode max stack size 20, 10 tags can be active simultaneously. Self-closing `[hr]` doesn't count toward stack but can't be used at 20. + +**Why it's a trap:** Complex channel descriptions with nested BBCode may be silently truncated or rejected. + +**How to handle:** Validate BBCode depth before sending. Truncate if exceeding limits. + +**Source:** YaTQA §1.8 + +## 11. Anti-Flood Server-Configurable (HIGH) + +**What:** Anti-flood thresholds are server-configurable, not fixed. Key variables: +- `AntifloodPointsTickReduce` — points deducted per 0.5-second tick (TeaSpeak default: 25) +- `AntifloodPointsToCommandBlock` — threshold to block commands (TeaSpeak default: 150) +- `AntifloodPointsToIpBlock` — threshold to block IP (TeaSpeak default: 300) + +**Why it's a trap:** Hardcoding flood thresholds will cause either over-aggressive throttling or server bans. + +**How to handle:** Read flood config from `serverinfo` response. Use conservative defaults. Implement client-side flood tracking (TODO-064). + +**Source:** YaTQA §5.1, ReSpeak §vars, TeaSpeak §vars + +## 12. TeaSpeak Query Newline Divergence (INFO) + +**What:** TeaSpeak changed ServerQuery line terminator from `\n\r` to `\n` in 1.4.14-beta6. TS3 uses `0x0A 0x0D`. + +**Why it matters:** If Chanora ever adds ServerQuery support, must detect server type. + +**How to handle:** Not relevant for voice client path (Chanora uses voice protocol, not query). Note for future reference. + +**Source:** TeaSpeak §divergence-2 + +## 13. TeaSpeak Strict UTF-8 Mode (MEDIUM) + +**What:** TeaSpeak has `strict_utf8_mode` config option that may reject non-UTF-8 strings. + +**Why it's a trap:** Strings that pass through TS3 servers may be rejected by TeaSpeak servers. + +**How to handle:** Ensure all outbound strings are valid UTF-8. Rust's `String` type guarantees this, but verify at protocol boundaries. + +**Source:** TeaSpeak §config