# Next Session: Adversarial Review Bugs — Phone Loop + TTS Filter

**Found during session 395 adversarial review (planning-with-review)**

All issues below were found by architecture and code quality reviewers. The 6 issues marked FIXED were addressed immediately. The rest need fixing in future sessions.

## FIXED (session 395)
1. ~~Image pattern must precede link pattern in _PATTERNS~~ → Fixed in tts_text_clean.py
2. ~~_PATTERNS was mutable list~~ → Converted to tuple
3. ~~Phantom _PATTERNS re-export in speech_text_filter.py~~ → Removed
4. ~~Partial JSON regex no re.DOTALL~~ → Added, multiline now handled
5. ~~Empty tts_text → silent dead turn~~ → Fallback utterance added
6. ~~13 inline test imports~~ → Module-level import

## BUG: Transcript loses assistant turn after compaction
- **File**: phone_loop.py:51-63
- **Issue**: `messages[-2:]` is not always the last user+assistant pair. After compaction, the slice could be `[system, user]`, silently losing the assistant turn.
- **Fix**: Scan explicitly for last two messages by role, not by position.

## BUG: Double-compaction on context_length_exceeded retry
- **File**: phone_loop.py:130-134
- **Issue**: Inside `_call_llm`, `_compact_messages` is called on context overflow. But the main loop (line 402) already compacts after each turn. Two compactions in sequence could over-compact.
- **Fix**: Track whether already compacted, or deduplicate.

## BUG: Barge-in exceptions silently swallowed
- **File**: phone_loop.py:454-458
- **Issue**: If `bargein_task.exception()` is not None (unexpected bug in detect_bargein), barge-in is silently treated as not fired. Real bugs hidden.
- **Fix**: Log when `bargein_task.exception() is not None`.

## BUG: TOCTOU race in CachedFile.read()
- **File**: prompt_builder.py:157-172
- **Issue**: `stat()` then `read_text()` are separate syscalls. Under `asyncio.to_thread()`, two coroutines could race on the cache update.
- **Fix**: Either threading.Lock or document the benign race.

## SECURITY: XML injection via workspace MEMORY.md
- **File**: prompt_builder.py:291-300
- **Issue**: MEMORY.md content can contain `</workspace_memory>` to break out of the data section. `_sanitize()` strips control chars/emoji but NOT XML tags.
- **Fix**: Escape `<` and `>` in workspace file content, or use a delimiter that can't appear in natural language.

## SECURITY: _sanitize() does not strip closing XML tags
- **File**: prompt_builder.py:195-201
- **Issue**: Any workspace file can contain `</rules>` to break out of XML containers.
- **Fix**: Strip or escape XML-breaking patterns in workspace file content.

## SECURITY: GPU heartbeat world-readable PID
- **File**: phone_loop.py:328-329
- **Issue**: Heartbeat file written with default umask (world-readable). Any local user can read PID and send signals.
- **Fix**: Write with mode 0o600.

## SECURITY: No greeting length/SSML guard
- **File**: phone_loop.py:332
- **Issue**: `greeting` param from CLI has no length cap or SSML tag stripping.
- **Fix**: `len(greeting) <= 500` guard + strip SSML tags.

## MAINTENANCE: Magic numbers in compaction
- **File**: phone_loop.py:35-36
- **Issue**: `_COMPACT_THRESHOLD = 20000` and `_COMPACT_KEEP = 12` with no derivation comment.
- **Fix**: Add comment explaining the heuristic.

## MAINTENANCE: build_rules_reminder() duplicates _FALLBACK_RULES with drift
- **File**: prompt_builder.py:319-337
- **Issue**: 7-rule reminder vs 13-rule fallback. No single source of truth.
- **Fix**: Have reminder read from workspace file or derive from fallback.

## PERFORMANCE: O(N²) compaction check
- **File**: phone_loop.py:402
- **Issue**: `_compact_messages` iterates all messages every turn. Total work is O(N²) across conversation.
- **Fix**: Track estimated_tokens as running counter, only call compact when over threshold.

## PERFORMANCE: WAV files accumulate during call
- **File**: phone_loop.py:413, 505-508
- **Issue**: All turn WAV files sit on disk until session end. Glob delete at end nukes cross-session files.
- **Fix**: Delete each WAV after playback. Use session-specific subdirectory.

## ARCHITECTURE: Token estimation inflated by raw markdown in messages
- **Issue**: Raw response_text (with markdown) stored in messages, inflates compaction token estimate.
- **Fix**: Minor impact — compaction fires slightly early. Could clean text before storing in messages.

## ARCHITECTURE: Hallucination rule is prompt-only, not structural
- **Issue**: Rule 9 in RULES.md is a soft guardrail. Nemotron Nano may not obey it.
- **Fix**: Future — retrieval-first guard or fact_check tool at tool boundary. Named-entity pattern check on response_text against system prompt content.
