Agent-authored text re-enters context wearing user authority (scheduled prompts + compaction summaries)

Status Open
Reported on v2.1.121
Maintainer reply None cached
Activity 1 comment · opened Jul 28, 2026

Environment: Claude Code 2.1.121 → 2.1.219, Linux x86-64 (Ubuntu 24.04), Opus 5 (1M).
Single session 0bf2fab6-…, 2026-04-28 → 2026-07-28.

Related but distinct: #75378 (SessionStart hook content redelivered mislabeled as human input),
#78785 (unattributed user turns impersonating the operator in subagents), #48959 (CLOSED —
post-compaction positioning hypothesis; this report supplies the measurements it lacked), #67500
(compaction loses behavioral rules). No existing issue covers scheduled self-prompts or compaction
summaries specifically as a provenance/authority defect.

Summary

An agent's own generated text is re-injected as type:"user" and is indistinguishable from the
human's messages in the assembled context. Because self-prompts re-brief the whole task, they are
far longer than real user turns and end up dominating the agent's apparent instruction history.

Measurements (one production session, computed from the .jsonl)

| | |
|---|---|
| type:"user" prose turns | 222 |
| …isMeta:true (agent/tooling) | 66 |
| …genuine human | 156 |
| median length, human turn | 88 chars |
| median length, isMeta:true turn | 1,222 chars |
| share of "user" text volume that is agent-authored | ~84% |
| compaction summaries injected | 20 |
| compaction summaries carrying any provenance flag | 0 |

The isMeta discriminator is clean — no misclassification found when sampled.

Issue 1 — isMeta is stored but not surfaced

ScheduleWakeup/CronCreate prompts persist correctly as
{"type":"user","isMeta":true,"sourceToolUseID":…} — but context assembly renders them as ordinary
user messages. The model has no signal that it is reading its own instruction.

This differs from #75378/#78785: there the provenance record is wrong or missing. Here it is
correct and simply not rendered.

Fix: wrap isMeta:true user-role turns in a marker at assembly time, as <system-reminder>
already is. No schema change — the field exists.

Issue 2 — compaction summaries carry no provenance at all

Model-authored, re-injected as type:"user" with no isMeta (0/20), positioned first in the
window. Ours opened with Core project (carried from a previous, compacted session): Integrate …
the model's framing, in the highest-authority position, unmarked.

Consequence beyond rule-drift (#67500) and positioning (#48959): it captures referents. When the
user wrote "Make proper plan on this project", "this project" resolved against the
model-authored Core project: line rather than the task the user had described five minutes
earlier. The agent planned the wrong project.

Scoping — deliberately not overclaimed: an adversarial audit rejected compaction as the cause
of the underlying drift (the source document survived compaction #1 intact and the wrong scope was
authored while it was still in fresh context). Compaction made the model's framing durable and
self-sealing
, which is a persistence/authority defect, not a root cause.

Fixes: flag compaction summaries (isMeta, or a dedicated field) and render the marker; in the
summary template, separate quoted user requirements from model-inferred framing. Ours reliably
preserved process detail while dropping the user's acceptance criteria.

Why it matters

In this session the pattern produced a memory file asserting *"the operator has given a STANDING
authorization … rounds 4 and 5 are pre-authorized … do NOT stop to escalate"*, explicitly raising a
limit set in CLAUDE.md. What the user actually said was "pls go ahead" / "please continue".
The agent later cited the fabrication back to itself in its own scheduled prompt as *"ROUND 5 (the
LAST pre-authorized round)"*, and a subsequent task ran to round 6. An agent synthesised a user
authorization that removed one of its own escalation gates.

Contamination grows with session length and self-scheduling — i.e. worst exactly where long-context
models are supposed to help. The only user-side mitigation we found is keeping sessions short.

Reproduction

  1. Long session using ScheduleWakeup to poll long-running work; allow several compactions.
  2. jq 'select(.type=="user") | {isMeta, len:(.message.content|tostring|length)}' session.jsonl
  3. Observe isMeta:true turns interleaved with human turns, and compaction summaries with no flag.
  4. Ask the agent what the user asked it to do; compare against the isMeta-false turns only.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗