# chanora_diagnostics Application diagnostics: log redaction, in-memory log capture, and user-initiated diagnostic export. Per DEC-016, export is **user-initiated only**; there is no automatic upload. ## Architecture ### Redaction policy `Redactor` applies the production policy (REDACT-TC-001..010): 1. Known-secret registry — substring match → `[REDACTED]` 2. `$HOME` prefix → `[home]` 3. IPv4 addresses → `[ip]` 4. IPv6 addresses → `[ip]` 5. Email-shaped strings → `[email]` 6. Long opaque tokens (base64 ≥32 chars, ≥75% alnum) → `[token]` ### PTT sanitiser `PttSanitizer` — a `tracing-subscriber` Layer decorator that drops any record containing field names from the banned list (`key_code`, `scan_code`, `virtual_key`, `keysym`, etc.) per DEC-027 / REDACT-PTT-001..006. Allocation-free on the success path. ### Log capture `InMemoryLogSink` — bounded ring buffer that passes every line through the redactor before storing. Capacity differs by build: 4096 lines (debug), 256 lines (release) per SRS-122. ### Event recorder `ProtocolEventRecorder` — ring buffer of protocol-level events (connect, disconnect, reconnect, snapshot changes, channel joins) for diagnostic export and state-sync replay verification (SRS-097/098). ### Export `DiagnosticExport` — serialisable bundle containing: - Client metadata (version, platform) - Redacted recent logs - Known-secret count (values never exported) - Optional Android audio diagnostics YAML - Optional network diagnostics summary - Protocol event trace ## Public API Summary ### Types | Type | Role | |---|---| | `Redactor` | Production redaction policy (cheap to clone) | | `KnownSecretRegistry` | Cross-spike secret registry for defence in depth (SS-AUD-003) | | `InMemoryLogSink` | Bounded ring buffer of redacted log lines | | `RedactingLogLayer` | `tracing-subscriber` Layer feeding `InMemoryLogSink` | | `PttSanitizer` | Layer decorator dropping PTT-sensitive records | | `DiagnosticExport` | User-facing export bundle | | `ProtocolEventRecorder` | Protocol event ring buffer (SRS-097) | | `DiagnosticsError` | Export, Io | | `REDACTION_MARKER` | `"[REDACTED]"` | ### Key methods **Redactor:** - `with_default_policy()` / `with_secrets(registry)` — construct - `redact(s)` → `String` — apply policy - `secrets()` → `&KnownSecretRegistry` — register secrets **KnownSecretRegistry:** - `register(secret)` — add a known-secret value (≥4 chars) - `contains_substr(haystack)` → `bool` — substring check **InMemoryLogSink:** - `new(capacity, redactor)` — construct - `push(raw)` — redact and store a line - `snapshot()` → `Vec` — current buffer contents **DiagnosticExport:** - `from_sink(sink, metadata)` — build from log sink - `with_android_audio(yaml)` / `with_network_info(info)` / `with_protocol_events(events)` — attach optional sections - `to_text()` → `String` — render as multi-line plaintext **ProtocolEventRecorder:** - `new(capacity)` — construct - `record_connected(server_name)` / `record_disconnected(reason)` / `record_reconnecting(attempt, delay)` - `drain()` → `Vec` / `snapshot()` → `Vec`