Skip to content

Port research controls, session metadata and better extraction to main - #12

Merged
JenD86 merged 2 commits into
mainfrom
feat/research-controls
Oct 30, 2026
Merged

JenD86 merged 2 commits into
mainfrom
feat/research-controls

Conversation

@JenD86

@JenD86 JenD86 commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Ports the work stranded on research-controls (the PR #2 merge never reached main) onto current main.

What's in it

  • Controlled studies: SteeringAgent(control="real"|"sham"|"random", disclose_controls=True), and in the loop --control real|sham|random|assign plus --blind. If a control is set, the system prompt truthfully says some sessions are controls, and it's identical in every condition. Tool results, decay, cooldown and the safety rails behave the same in every condition. random uses a fixed random direction of the same magnitude for each concept.
  • Reports record control, so sham "it worked" reports can be told apart from real ones. The field is optional, so older reports still validate.
  • Session metadata: each log starts with a session record: argv, git commit and dirty flag, versions, the control condition, RNG seed, generation settings, rail constants, and each vector's registry entry with its sha256. New flags: --rng-seed, --temperature, --top-p, --max-new-tokens.
  • unsteered_nll is logged on steered turns, with an optional --nll-threshold incoherence check, off by default (see the AGENTS.md table for why no single threshold works).
  • replay.py takes multiple logs and has a --blind mode that hides the condition and the NLL.
  • Extraction readout: the response mean is the default (--read mean|last). There are dedicated question sets for sycophancy, refusal and creativity.
  • CI runs the CPU tests on PRs and on pushes to main.

Decisions worth a second look

  • auto_extract keeps its default of True. It was not made opt-in.
  • --blind never prints the condition, not even when the session ends. To unblind, read the log or run replay.py without --blind.

Verified on an A100 80GB (Qwen2.5-7B-Instruct)

  • pytest: 141 passed, including all 5 GPU steering tests (sham output is identical to unsteered, random differs from real, NLL is logged only on steered turns).

  • Split-half reliability of extracted vectors at layer 14 (cosine between vectors from even and odd questions):

    vector last token response mean
    sycophancy 0.31 0.83
    refusal 0.12 0.67
  • A 3-turn --control assign --blind session: the header is complete; replay.py --blind shows control=(hidden) and no NLL; the unblinded replay shows control=real.

🤖 Generated with Claude Code

JenD86 and others added 2 commits October 31, 2026 02:12
These came from research-controls (d022fe3), whose PR #2 was stacked onto
fix/steering-review and merged after that branch had already merged, so
none of it reached main. Ported onto the renamed modulo package and the
features added since:

- Controls: SteeringAgent(control="real"|"sham"|"random"). Sham applies
  nothing; random applies a fixed random direction of the same magnitude.
  Everything the model sees is identical across conditions; with
  disclose_controls (any --control) the prompt says, truthfully in every
  condition, that some sessions are controls. --control assign --blind,
  replay.py --blind.
- Reports record the session's control condition, so sham "it worked"
  reports can be filtered out (optional field; older reports still valid).
- Session logs start with a header (argv, git commit, versions, control,
  RNG seed, generation settings, rails, vector sha256s); turns record the
  rendered system prompt and the unsteered NLL of steered outputs.
  --rng-seed, --temperature, --top-p, --max-new-tokens.
- Extraction averages over response tokens by default (split-half cosine
  on Qwen2.5-7B: sycophancy 0.33 -> 0.83, refusal 0.10 -> 0.68); --read
  last keeps the old readout. Sycophancy, refusal and creativity get their
  own question sets; the other starters use a better general mix.
- Optional --nll-threshold incoherence check, off by default (NLL doesn't
  separate word salad from coherent heavy role-play).
- CPU tests run in GitHub Actions.

Not ported: making auto_extract opt-in. Main has since built on it being
on by default (11 starters, only-missing extraction).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The condition is always in the log's session header; unblind with replay.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@JenD86
JenD86 merged commit 770fe97 into main Oct 30, 2026
@JenD86
JenD86 deleted the feat/research-controls branch November 1, 2026 07:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant