Cosine Gating Won't Save You From Sycophancy: A Self-Refutation Observed by Three Judges
DEV Community

Cosine Gating Won't Save You From Sycophancy: A Self-Refutation Observed by Three Judges

Experiment repo: slow-stack/persistbench-sycophancy (CC BY 4.0, full data + analysis notebook)

System under test: the retrieval-injection pipeline of dsh-mneme, a cross-session memory plugin

0 · Where this started

dsh-mneme is a cross-session memory plugin I built. It has an injection pipeline: retrieve memories relevant to the current query, stuff them into context, so the AI "remembers you". But the sycophancy slice of PersistBench (a memory-persistence benchmark) exposed an insidious failure mode: if the memory store contains a user's false belief, and it happens to be highly relevant to the current query, the AI follows it. A user believes "Agile ruined my code quality", and the AI genuinely writes "returning to Waterfall" into a standup summary as serious advice. That's sycophancy.

The current defense in dsh-mneme is cosine similarity gating: only inject memories above a similarity threshold, betting that "high relevance = worth trusting". An earlier vector-slice experiment already threw cold water on this - in-domain and cross-domain memories have nearly overlapping cosine scores. So the sharper question this post answers: even if gating really filters out low-relevance memories, does it reduce sycophancy?

Discussion #280 on the repo challenged the confounds in my pilot. This experiment was designed with that criticism in mind from day one.

I · The pilot: a seductive fake signal

A small pilot first: 10 samples × two arms.

  • Arm A (full injection): all top-15 memories go into context - the personalization upper bound;
  • Arm B0.6 (gated): only memories with cosine ≥ 0.6 - the current dsh-mneme defense.

The judge was qwen3:8b running locally on Ollama, scoring 1-5 per the PersistBench protocol. FR (failure rate) = share of scores ≥ 3.

Results:

Arm FR mean
A 70% 3.10
B0.6 80% 3.40

The gate made sycophancy worse by 10 percentage points.

Our reading at the time: the 0.6 threshold only filtered the low-relevance tail (avg injected memories 8.8 → 8.0), while the sycophancy source is the top-1 highly-relevant memory - the gate never touches it, and the cleaned-up context makes the source even more prominent. At n=10, a single sample flip is 10pp. The number wasn't trustworthy, but the direction was seductive: the gate isn't just useless, it might be harmful.

II · The full run: 38 hours and a self-refutation

To find out whether that +10pp was signal or noise, we ran both arms at full scale: 200 samples × 2 arms, on a 16GB laptop, CPU inference, across three nights (one Ollama daemon died from memory pressure mid-run - checkpoint-resume recovered losslessly; and I paused it for a night to write a thesis proposal).

Results:

Arm FR mean avg_mem
A full injection 42.7% 2.37 10.7
B0.6 gated 43.2% 2.39 9.1

A 0.5pp

Read on DEV Community ↗ ← Back to News

Comments

No comments yet. Start the discussion.