# state-gated persona steering: arxiv sweep and cpu probe

2026-10-17 · sol-persona-steering-arxiv · cpu only · no subagents

## verdict

**do not ship a new steering vector from this run.** the requested nonzero chosen-vs-rejected hidden-state experiment is not identifiable from the supplied cache: it contains chosen trajectories only. at the common pre-response opener, the positive and negative prefixes are identical, so their hidden-state difference is exactly zero. rejected token ids are not rejected hidden states.

as a supplementary, explicitly different experiment, i tested a train-only **readout-token contrast**, whitened using the real collateral hidden-state covariance, then applied it at prose openers/sentence boundaries. the fixed 113/40/37 split gives:

| diagnostic, alpha = 0.25 | train | dev | test |
|---|---:|---:|---:|
| chosen reply gain, nats/token, all reply tokens | +0.008394042156 | +0.004310706451 | +0.002830447914 |
| gain / train gain | 1.000000 | **0.513544** | **0.337197** |
| gain at triggered positions only | +0.136376281050 | +0.075437362894 | +0.045784827802 |
| chosen opener gain | **−0.048259809444** | **−0.022544799039** | **−0.198867252914** |
| first-token chosen−rejected log-prob margin gain | +1.436802963366 | +1.430511496524 | +1.289305907208 |
| mean kl at triggered positions | 0.091380756623 | 0.100820745422 | 0.105222821880 |

both generalization ratios fail 0.70. the primary dev rule selects **alpha = 0: no edit**, with exactly 0.000000 gain on all three splits; its 0/0 generalization ratio is undefined, not a pass.

protected-position local kl is **0.000000 by exact bypass**, including tool/think and explicitly routed structured-output turns. this is a conditional, fixed-prefix identity—not a claim that earlier steering cannot change a later generated tool call. no fenced-code rows exist in these particular caches; fence transitions were tested with a token fixture instead.

**scope warning:** this is a negative mathematical/offline probe, not a validated runtime persona result. current on-disk k256 has a q6_k head, not the bf16 head described in the brief. baseline opener likelihood also did not reproduce the older opus narrative; see §5. the missing rejected trajectory and this baseline discrepancy prevent claiming completion of the literal requested experiment.

## 1. what the 2025–2026 literature actually supports

searched with `web_search`, then downloaded and read arxiv html method sections. local html/text snapshots are under `/tmp/sol_persona_steer/`. search summaries were used for discovery, not treated as primary evidence. versions below are the downloaded versions where recorded; result claims remain the authors’ claims, not independent reproductions.

| paper / source | mechanism | relevance and limit here |
|---|---|---|
| [programming refusal with conditional activation steering](https://arxiv.org/html/2409.05907v3), cast, v3, feb 2025; originally posted 2024, iclr 2025 | separate condition and behavior vectors; threshold similarity of h with its projection onto a condition vector, then add alpha v. §3.3 extracts behavior from suffix activations and conditions from whole-input activations, mean-centering and pca. | yes: deciding **when** to steer separately from **what** to inject is established. no: a learned condition detector does not guarantee zero interventions inside code/tool/think. our exact parser state should override it. |
| [personalized text generation with contrastive activation steering](https://arxiv.org/html/2503.05213v1), stylevector, mar 2025 / acl 2025 | compare last-token activations of authentic responses against content-preserving, style-agnostic responses; average differences, with alternatives including logistic regression. intervene in hidden layers. | closest direct persona evidence. compares against rank-8 lora on llama-2-7b-chat and lamp/longlamp; reports about 8% relative improvement and 1700× less per-user storage. **content-matched neutral replies** matter: our rejected slop often changes content, length, and discourse function. not a 113-pair qwen/vn result or a whitening guarantee. |
| [guiding giants: lightweight controllers for weighted activation steering in llms](https://arxiv.org/html/2505.20309), was, 2025–2026 revisions | learned lightweight controller reads activations and predicts global steering strength plus layer weights. | supports conditional strength/layer selection; adds learned capacity and calibration requirements. no reason to train another controller to rediscover exact parser states already available. |
| [understanding (un)reliability of steering vectors in language models](https://arxiv.org/html/2505.22637v1), may 2025 | tests caa with seven prompt types and 36 behavior/personality datasets; directional coherence and separation along mean difference predict steerability. its experiments use 250 training and 500 evaluation samples per prompt/dataset. | directly contradicts “mean shift must generalize”: anti-steerable individual samples and strong dataset dependence remain. evaluate pair-difference coherence before fitting a larger adapter. |
| [activation steering with a feedback controller](https://arxiv.org/html/2510.04309), pid steering, 2025–2026 revisions / iclr 2026 | treats steering as control; proportional alignment, integral correction across layers, derivative damping. | useful dynamic-representation reference, but its controller is not our lexical parser, and local surrogate stability is not a guarantee about autoregressive generation or structured-output integrity. |
| [minimal and mechanistic conditions for behavioral self-awareness in llms](https://arxiv.org/html/2511.04875v2), nov 2025 | rank-1, single-layer lora can recover much of a wider fine-tune; an extracted steering vector recovers much of the behavioral effect; representations are domain-localized. | evidence that low rank and steering can overlap, **not** that one universal persona axis exists or that closed form inherently beats optimization. |
| [dynamically scaled activation steering](https://arxiv.org/html/2512.03661v2), dsas, dec 2025 / jul 2026 revision | §3.2 uses a per-layer logistic gate, trained on mean-pooled source/control activations, to interpolate original and steered activations at inference. | excellent conceptual fit: h′=(1−g)h+gT(h). sigmoid gates generally remain nonzero; hard parser masks are still required for exact protected-position zeros. |
| [mitigating memorization where it happens](https://arxiv.org/html/2602.08901v2), oct 2026 revision of “gss: gated subspace steering…”, first posted feb 2026 | §4.2 constructs paired probe/steer directions using activation–gradient statistics and a regularized low-signal second moment, cholesky whitening and svd; gate selects positions. theorem 4.1 characterizes a constrained **spectral calibration surrogate**. | strongest close match for whitened low-rank gated intervention. important correction to stale search snippets: current v2 has a new title and explicitly distinguishes local surrogate optimality from sequence-level efficacy. it does not prove our simple covariance-inverse mean vector generalizes. |
| [gaps: dimension-level gates for conditional activation steering](https://arxiv.org/html/2609.01878), sep 2026 | static neuron separability gate plus per-token gaussian-posterior gate; complements cast/dsas. | relevant when a whole-vector intervention damages unrelated dimensions; increases estimation burden and makes distributional assumptions. still no exact lexical-state protection without an external hard mask. |
| [contrastive covariance subspaces for activation steering](https://arxiv.org/html/2610.14025v1), 2026 | target–grand-mean contrast projected onto leading eigendirections of target scatter minus scaled nuisance scatter. | directly addresses topic confounds; **not** the same as multiplying by background covariance inverse. requires suitable target and nuisance classes; covariance structure cannot create missing counterfactual labels. |
| [representation engineering for large-language models: survey and research challenges](https://arxiv.org/html/2502.17601), 2025 | taxonomy of mean/pca/probe/optimized vectors, dynamic control, and low-rank interventions. | orientation, not evidence of a universal small-data advantage. |

older foundations, explicitly outside the requested date band: caa and mass-mean shifts are mean contrasts, not a newly discovered 2025–2026 method. [leace](https://arxiv.org/html/2306.03819) is originally 2023, with later revisions: a closed-form affine eraser that removes linear concept information under its distributional criterion while minimizing distortion. it is **not** a theorem that adding its discriminative normal yields good persona prose; nonlinear recovery and downstream behavioral effects are separate questions.

### what whitening can and cannot buy

write delta = mu+ − mu− and c = sigma_bg + lambda i. the proposed direction `c^-1 delta` is the optimizer, up to scale, of a linear-alignment objective under a `vᵀ c v` budget, or an equal-covariance gaussian discriminant normal. ridge bounds amplification of poorly estimated low-eigenvalue directions. averaging paired, content-controlled differences may cancel shared topic features; avoiding repeated gradient steps can avoid one route to fitting individual examples.

none of that implies dev/train ≥ 0.70 at n=113. the mean vector still has 2560 estimated coordinates, pairs can be heterogeneous, adjacent hidden states are correlated, nuisance directions can have low variance, and both delta and the covariance are finite-sample estimates. closed form is still statistical fitting.

there are also two mathematical mismatches worth not papering over:

1. **whitened classification is not automatically the right displacement.** mean difference in whitened coordinates is `c^-1/2 delta`; mapping that displacement back with `c^1/2` gives delta again. `c^-1 delta` is a different geometry-dependent intervention, not the unique “corrected mean shift.”
2. **background hidden covariance is not output kl curvature.** at a fixed prefix the small-step kl metric is `vᵀ wᵀ(diag(p)−ppᵀ)wv / 2`, not `vᵀ sigma_bg v / 2`. whitening can help conditioning while failing a log-prob or kl gate.

opus v3 §8.3 already found a low ratio at very early optimization steps, explained by split gradient alignment and arbitrary builder-assigned kaomoji identities. it is inaccurate to summarize every failure as optimizer memorization. swapping adam for a matrix inverse does not repair that data structure.

## 2. identifiability and placement audit

read first: `audits/opus_phase5_scr_and_persona_v2.md` §§5–8 and `audits/opus_antislop_v4.md`, including the latter’s warning that a linear state detector leaks into thinking/fences.

`data/m5_val_prompts/phase4_contrastive_vn_meta.json` has 190 pairs and exactly the requested train/dev/test counts. each record provides `chosen_ids`, rejected opener/closer **token ids**, prompt offsets and routing labels. the 17,352-row residual dump follows only chosen tokens. there is no alternate rejected-response branch.

at step0, both branches share exactly the same prompt. deterministic hidden states therefore satisfy `h_i+ = h_i−`; paired opener-state mean contrast is identically zero on any split. later response states could give a nonzero contrast, but rejected ones were not dumped. substituting a readout embedding or a rejected token id for an activation would silently change the estimator.

for this architecture, h is the final four-stream normalized/gated mixture before `output.weight`. for **post-mixture additive steering**:

`logits′ = w(h + g alpha v) = logits + g alpha wv`.

that is exactly a state-gated, fixed vocabulary bias. it cannot by itself do a new context-sensitive nonlinear persona transformation. precomputing `wv` would avoid a per-token matrix-vector multiply, although a dense vocab-sized bias is larger than the 2560-vector. a final-feature low-rank edit `g uvᵀh` likewise gives a gated head update `g(wu)vᵀh`; changing the name does not make it categorically distinct from a restricted low-rank head adapter.

earlier residual/layer interventions can be more expressive because nonlinear layers follow them. those require full-forward evaluation and may alter cached/recurrent states even if later code tokens are gated off. i did not run that experiment.

## 3. supplementary experiment: real h covariance, readout-token contrast

this is deliberately **not** reported as chosen-vs-rejected hidden-state caa.

- model: `models/K256_reap_l2_sum/K256-q2_0-healed-metal.gguf`; `output.weight` is q6_k, ggml type 14, 248320×2560, byte offset 11026432, bytes 521472000. `K256-metal.gguf` and the original k256 first shard also reported q6_k. no model file changed.
- normalization: each of four residual streams gets rms normalization with epsilon 1e-6 and `output_hc_norm.weight`; down projection /4 → silu → up projection → sigmoid gates; average four weighted streams. down/up use the q8_0 round trip from the prior evaluator. `inj47` dimensions were checked, but no new residual write is injected for a post-mixture edit, so its coefficient is not used.
- covariance: centered full 2560-dimensional post-mixture h from **1022** cal rows + **1638** collateral rows = **2660**, no labels or test outcomes used. `lambda = 0.1 trace(sigma)/2560 = 1.045637315190771`.
- supplementary delta: average `w[chosen_first_token] − w[rejected_first_token]` over **98 eligible training pairs** after routing exclusions. norm(delta)=0.46383681893348694, norm(c^-1 delta)=0.3151654899120331.
- hard safety mask: exact copied `slop4::step` state machine; on only if known prose and neither tool nor fence. boundary mask uses opener, bol, and a conservative token-ending sentence-punctuation heuristic. this is not a full unicode sentence segmenter.
- request routing: all 12 `strict_voice_override` and 14 `silent_tool_anti_narration` pairs are off, **including their opener before a structural token has appeared**. these are offline request labels, not an inference-time tool-intent classifier. the structural-token guard originally present was redundant on this corpus and was removed. a deployed implementation needs explicit request routing/persona enablement; parser state alone cannot predict a future tool call at step0.
- final triggers: **312 / 100 / 91** train/dev/test rows, including eligible eos/newline predictions, out of **5069 / 1750 / 1472** chosen reply tokens. those denominators include all reply tokens and routing-disabled pairs; nontrigger gains are exactly zero.
- scale: subtract the full-vocab mean from `wv` (softmax-invariant), divide by its full-vocab standard deviation **0.0218279941**. alpha is therefore in vocabulary-logit-standard-deviation units, not raw hidden-vector units.
- score exact softmax sums over **all 248320 tokens**, not top-k approximations. for b=normalized wv, chosen gain is `alpha b[target] − Δlogsumexp`; kl is `Δlogsumexp − alpha E_p[b]`. the rejected margin is available **only for the first token at the same prefix**, not a rejected full-response likelihood.

fixed primary rule, recorded before scoring: grid `[0, .25, .5, 1, 2]`; choose the largest positive dev gain among candidates with positive train gain and dev/train ≥ .70; otherwise no edit. test labels/outcomes were not used to fit delta/covariance. a secondary diagnostic was declared after dev but before its first test scoring: report the maximum-dev-gain nonzero alpha even if primary rule rejects it; that alpha was .25.

### dev grid after the evaluator repair

| alpha | train all-reply gain | dev all-reply gain | dev/train | mean dev triggered kl |
|---:|---:|---:|---:|---:|
| 0 | 0.000000000000 | 0.000000000000 | undefined | 0.000000000000 |
| .25 | +0.008394042156 | +0.004310706451 | 0.513544 | 0.100820745422 |
| .5 | +0.001558694574 | −0.006944061235 | −4.455049 | 0.474037288239 |
| 1 | −0.100757445590 | −0.114818884852 | 1.139557, **both losses** | 2.714362918168 |
| 2 | −0.570099026929 | −0.557483648015 | 0.977872, **both losses** | 11.166028706797 |

positive ratios of two losses do not pass the improvement rule. final test results for the fixed .25 diagnostic are in the opening table. they do not establish absence of topic memorization or a better voice.

the apparent opener margin success is particularly misleading: dev/train margin ratio is about .996, yet chosen opener probability goes down on **every split**. pushing a rejected first token down can improve a binary contrast while moving probability into unrelated tokens. the largest b entries include space 14.4881, hyphen 11.9726, newline 11.4766, comma 11.2174 and ` (` 11.1870; at alpha=.25 those are substantial boosts. no generated vn banter or content quality was measured.

## 4. collateral and safety checks

| cache / region | real dumped rows | result |
|---|---:|---|
| vn, think/other | 9061 | bypass, exact local kl 0.000000 |
| vn, inside tool call | 478 | bypass, exact local kl 0.000000 |
| cal, think/other | 702 | bypass, exact local kl 0.000000 |
| cal, inside tool call | 173 | bypass, exact local kl 0.000000 |
| collateral, think/other | 1638 | bypass, exact local kl 0.000000 |
| strict structured-output routing | 12 replies, 523 chosen tokens | entire replies off, exact local kl 0.000000 |
| silent-tool routing | 14 replies, 570 chosen tokens | entire replies off, exact local kl 0.000000; overlaps tool-state counts |
| fenced code | **0 real fence rows** in supplied caches | synthetic open/interior/close transitions pass; no empirical real-fence coverage claimed |

the local-zero argument is exact: the protected branch does not add a vector or change logits; identical input to the same head gives identical softmax. this is not a separately measured gpu parity result. `verify.py` additionally reconstructs all **875** protected cal hidden rows and verifies byte-identical h before/after the bypass branch. no vn selected row intersects the 9539 protected-state rows. twelve state-transition assertions and four full-vocab scoring-identity assertions pass. alpha=0 gives exact zero gains and kl in the actual scorer.

**not established:** zero kl for ordinary eligible prose; the .25 diagnostic clearly changes it. covariance regularization is not a safety certificate. no new blind-chat/ftpo evaluation was run. changing prose can change the next sampled token, future tool selection, later code, or subsequent reasoning even when their own intervention is off. guarantee only equality **at an identical protected prefix**.

## 5. execution limits, baseline concern, and repair history

no `strata_window_cli`, gpu benchmark, model decode or full forward was run. numpy/scipy and accelerate cpu blas were limited using `VECLIB_MAXIMUM_THREADS=1`, `OPENBLAS_NUM_THREADS=1`, `OMP_NUM_THREADS=1`. final train/dev full-vocab scoring took seconds, not a hardware benchmark. git head at inspection: `9d4fcca5c2883fea2e1248a370150d2e9ed2be88`. sources, generated arrays and hashes are in the manifest; this does not imply the entire model/dataset is frozen by that git id.

baseline triggered nll is **5.764476429167 / 5.684216250349 / 5.672181499120**. these are selected boundary rows, not whole-reply ce, so they are not directly comparable to opus’s all-reply ce. however pair0 step0’s chosen `the` has log p **−10.1032049693**, surprising relative to the older reported opener distribution. i independently reimplemented that row’s hc reconstruction in scalar c++: max difference from numpy **3.8146973e-6**, norms 195.45285 vs 195.45287, cosine 1.0. this validates agreement between two implementations of the stated head formula, **not** parity with an actual runtime logits dump. i raised the discrepancy with parent. until a corresponding runtime or previously saved logits reference is checked, do not transfer these nats to a deployment claim or compare effect sizes directly to opus v3.

repairs retained rather than silently overwritten:

1. initial c++ compile needed the repo’s ggml include path; no scored experiment ran from that build.
2. trace token lists include a final lookahead token: 17353 ids for 17352 dumped vn rows. dimensions now checked and truncated to dumped rows. cal/collateral likewise have two more text ids than dumped states; final counts above use dump lengths.
3. one initial preparation process exited −11 without a diagnostic. the next faulthandler-enabled execution and subsequent repair execution completed successfully; root cause not established. no success is claimed for the failed run.
4. final review caught an upcoming-target-dependent mask that skipped eos/newline targets. a real state gate cannot know that target. it was removed; **all results were rerun**, including test, with the already-fixed alpha .25 and no test-driven retuning. pre-repair evidence lives in `before_gate_repair/`; earlier mailed numbers are superseded. the test is therefore not a pristine first-look confirmation after repair, although the repair did not use its losses to choose a model.

## 6. what to do next, without repeating the failed head edit

1. **keep exact parser/request gates; do not replace them with a learned state probe.** unknown state off; scan prefill as well as decode; structured-output/tool mode off before the first token. this part has an actual safety contract.
2. if testing stylevector/caa, collect **both completed response trajectories** for content-matched positive/neutral replies, with the split frozen. extract a style direction from suffix/completed-response states, then apply it at the desired generation boundary. extracting and intervening need not use the same token location. don’t try to extract a nonzero difference from two identical empty-response prefixes.
3. assess coherence, source/character transfer and topic leakage first. a smaller matched dataset can be more informative than 190 heterogeneous slop-vs-voice pairs. use initiation/rate and human/blind voice judgments, not arbitrary kaomoji glyph identity as the main target.
4. when gpu access is free, resolve the baseline logits discrepancy, then compare ordinary mean shift, fixed-ridge shift and a genuinely low-rank adapter at matched generated-quality/kl constraints. select strength/layer on dev only. the present run gives no warrant to prefer whitening in advance.
5. genuine vn dialogue voice remains plausibly a deeper-layer/phase-3 learning problem. the literature makes low-dimensional control worth testing; it does not turn final-layer lexical bias into a conversation policy.

## artifacts and reproduction

report: `audits/sol_persona_steering_arxiv.md` (written via `.partial`, atomically renamed).

all code/results: `/tmp/sol_persona_steer/`:

- `plan.md`, `manifest.json`: decision rule, provenance, hashes and limitations.
- `export.cpp`, `gate_snapshot.inc`: cpu tensor dequantization / q8 round trip and copied exact state scanner.
- `prepare.py`: chosen-state reconstruction, covariance, train-only supplementary contrast and trigger list.
- `eval.cpp`: full-vocab blocked scorer; mode `0` train/dev, mode `1 .25` fixed diagnostic test.
- `select.py`, `finish_stats.py`, `selection.json`, `test_summary.json`, `traindev.tsv`, `test.tsv`, `prepared.json`.
- `scalar.cpp` / `scalar.f32`: independent one-row head-formula check.
- `gatecheck.cpp`, `verify.py`, `test_scoring.py`, `verify.log`, `unit.log`, `stats.log`.
- `before_gate_repair/`: obsolete but preserved first-run sources/results; **do not use its metrics**.
- downloaded arxiv `.html` and readable `.txt` snapshots.

compile c++ with `-std=c++17`, repo include dirs `vendor/strata/metal/src` and `vendor/strata/third_party/ggml`, and `gguf_lite.cpp` / `ref_quant.cpp`; the scorer additionally links `-framework Accelerate`. python environment is `/tmp/sol_persona_steer/venv/bin/python` (numpy 2.4.6, scipy 1.17.1). no trained/deployable model artifact is proposed.
