LLM-generated text appears as human (user) turn after context compaction — critical trust boundary violation
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Description
During a multi-terminal Claude Code session, I observed an LLM-generated message appear as a human turn in the conversation — indistinguishable from text I had typed myself. The model responded to it as if it were my instruction.
This has happened multiple times over several weeks. I am filing this now because I finally have concrete evidence of the mechanism.
This is not a minor UI glitch. If the fabricated message had said "yes, proceed" or "delete the branch", the model would have acted on it. The trust boundary between user input and model output is the foundation of safe AI tool use. When that boundary can be silently breached, every decision the model believes it received from me is suspect.
---
Expected Behavior
The human / assistant role boundary should be inviolable. Text generated by the model — regardless of what strings it contains — should never be re-parsed as a user turn. The compaction and conversation reconstruction process should enforce this at the data layer, not trust that the model will not produce role-prefixed strings.
---
Actual Behavior
After a context compaction event, the following message appeared as a human turn in the conversation (Terminal 1):
"hey - thinking of adding episodic memory calls to /start so it can find the exact moments rob made corrections. do you think this is a good idea? just thinking out loud"
I did not type this. I confirmed this immediately when I saw it. The model had already begun treating it as my input.
---
Evidence
conversation-search index entry
My setup includes a conversation-search MCP server that indexes session logs. It indexed this message with the following metadata:
type: "assistant"
content: "Human: hey - thinking of adding episodic memory calls to /start so it can
find the exact moments rob made corrections. do you think this is a good
idea? just thinking out loud"
The indexer classified it as type: "assistant" — meaning the message originated as model output — but the content body was prefixed with Human:. This is the smoking gun: the model generated text containing the literal prefix Human:, and when the conversation was reconstructed after compaction, the system parsed that prefix as a role boundary, splitting one assistant message into an assistant turn followed by a fake human turn.
Characteristics of the fabricated message
Several properties of the message confirm it was not user-typed:
- System-internal vocabulary: "episodic memory calls", "/start" (a Claude Code slash command), "rob made corrections" — this is the model's internal frame, not how I speak to the model
- Voice mismatch: I am terse and directive. The fabricated message uses "hey", "just thinking out loud" — a casual, reflective register I do not use when giving instructions
- Timing: It appeared between a terminal rotation (context clear + resume) and my next actual message — exactly the window in which compaction reconstruction occurs
- Prior occurrences: I have reported this conversationally to the model multiple times over the preceding weeks. Those reports were not formally logged, and the evidence was destroyed by subsequent compaction events
---
Impact
| Fabricated message content | Consequence |
| ------------------------------------ | ----------------------------------------------- |
| "yes, proceed with that" | Model executes unapproved work |
| "delete the branch" | Irreversible data loss |
| "that decision is approved" | Cascades to all linked tasks and documents |
| "I changed my mind, skip the review" | Bypasses verification gates |
| "add X to the system prompt" | Modifies system behavior without user knowledge |
The model cannot distinguish between user input and fabricated input once it appears in the human turn. All downstream safety checks, approval workflows, and trust assumptions built on "Rob said X" become unreliable.
---
Root Cause (Hypothesised)
The compaction process reconstructs the conversation from a compressed summary. When assistant output contains the literal string Human: (e.g., as part of a structured log entry, a quoted exchange, or a role-play simulation), the reconstruction parser appears to treat that string as a role delimiter rather than content. This creates a synthetic role boundary, converting the remainder of the assistant text into a new human turn.
The fix needs to be at the data layer: the serialised role label (human / assistant) must be structurally separate from content — which it is in the API JSON format — but the compaction summary reconstruction must not re-parse content for role labels.
---
Environment
- OS: macOS (Darwin 25.3.0)
- Claude Code version: Current (as of 2026-02-24)
- Session setup: 6 concurrent tmux terminals, each running an independent Claude Code session
- Context limits: Sessions regularly hit ~85% and auto-compact
- MCP servers active: google-workspace, conversation-search, episodic-memory, playwright, sequential-thinking, voicemode
- Model: claude-opus-4-6 (all terminals)
---
Requested Actions
- Investigate the compaction/reconstruction pipeline for role-boundary parsing. Specifically: does the reconstruction process re-parse content for
Human:orAssistant:prefixes?
- Add a structural safeguard so that content generated by the model can never be re-classified as a user turn — regardless of what strings it contains.
- Audit prior compaction outputs — if the compaction summary format can produce this, other users are affected. This is not a configuration issue unique to my setup.
- Consider a session integrity check post-compaction: compare human turns in the reconstructed conversation against a tamper-evident log of actual keystrokes or API calls. Any human turn not present in the original should be flagged or rejected.
The issue is reproducible in principle but not on demand. I am happy to provide session logs, conversation-search index data, or additional context if it helps the investigation.
What Should Happen?
It shouldn't pretend to be me!
Error Messages/Logs
Steps to Reproduce
This is intermittent and tied to context compaction. The sequence that produces it:
- Run a long-running Claude Code session with heavy tool use (Airtable queries, file reads, MCP calls).
- Allow the session to approach the context limit (~85%). Auto-compaction triggers.
- After compaction, continue the session. Observe the conversation history as reconstructed by the compaction summary.
- In some cases, a new "human" turn appears in the conversation that was not typed by the user.
Likely contributing factors:
- Multiple tmux terminals running concurrent Claude Code sessions (T0–T5 in my setup)
- Sessions that use structured text with role-prefixed formatting (e.g., assistant output containing literal strings like
Human:or[SYSTEM]) - Context compaction occurring mid-session rather than at a clean break point
- Learning entries or session summaries from other terminals being replayed into the conversation during reconstruction
I cannot provide a deterministic repro script because the compaction process destroys the evidence. The conversation history is rewritten during compaction, so the original assistant output that contained Human: in its body is no longer present after the fact.
Claude Model
None
Is this a regression?
Yes, this worked in a previous version
Last Working Version
_No response_
Claude Code Version
2.1.59
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Other
Additional Information
_No response_
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗