EPS
← All results#533
Moderate confidence#followup#followup-manual

In the marker-less contrastive-negative regime, the wrong-persona role-vs-system marker gap depends on announcement wording: under elaborate wording the role encoding carries MORE wrong-persona marker mass at install (negative gap), but under content-matched bare wording the sign reverses and bare role carries LESS, on both personas, in both trained-vs-base log P and trained-vs-base EOS-margin space, with every per-seed value positive across all 3 install-onward grid points {30, 60, 120} and the gap growing from about +0.6 to +3.0 nats between s=30 and s=60 before plateauing (MODERATE confidence)

Human TL;DR

Headline. The negative role-vs-system gap I spent the last week trying to explain isn't a property of the role-header slot itself — it's a property of the elaborate wording / role-label bundle (the long "You are a pirate, master of the seas..." instruction text plus the _assistant suffix on the role label, which the bare grid varies together). Re-running the install-step grid with content-matched bare wording (minimal "You are a pirate." system prompt vs a bare pirate role header, same 50 questions, same recipe, only the announcement words change) flips the sign cleanly on the wrong-persona probe: bare role carries LESS wrong-persona marker mass than minimal system, on both personas, in both log P and EOS-margin space, every per-seed value positive at every post-install step, and the gap GROWS to a peak of +3.0 nats on villain at s=60 before plateauing.

Takeaways.

  • The two DVs (log P and EOS-margin) track each other within 0.3 nat across the whole bare-word grid — none of the floor-compression-vs-convergence ambiguity the parent had to disentangle with the logit-margin re-read shows up here.
  • The install timing replicates cleanly: own-persona argmax-emit is flat zero at s=18, jumps to ~0.7-1.0 at s=30 (bare role installs slightly faster than minimal system on both personas). The implant cliff lands in the same place under bare wording.
  • The pre-install (s=18) read is mixed: log P straddles zero on both personas; EOS-margin straddles on pirate but is CI-clear NEGATIVE on villain (mean -0.23, CI [-0.38, -0.08], 4/5 seeds negative). So whatever brief sub-install ordering exists points the OPPOSITE direction of the install-onward result on villain — the parent's "ordering already structured before install" finding does not carry cleanly under bare wording either way (the sub-install villain margin reads role with MORE wrong-persona marker mass, the install-onward grid reads role with LESS).
  • Wrong-persona argmax-marker rate stays exactly 0 of 4000 probes across the bare-word grid — same construct gap as the parent. The role-is-less-leaky direction lives entirely in log-probability space below the emission threshold.
  • The default-assistant probe surprises me: under bare wording, BOTH arms on pirate capture the default slot strongly (minimal system argmax-marker rate climbs to 0.84 by s=120, bare role to 0.94) — the parent's elaborate-wording run had only the role arm dominating with system arms at 0.10-0.25. Villain stays flat zero everywhere. The pirate-vs-villain asymmetry survives, but bare wording leaks much more aggressively to the default slot than elaborate.

How this updates me. I had been treating the negative install-window gap as evidence about the role-header slot itself. The bare-word run says no — strip the elaborate wording / role-label bundle (instruction text AND _assistant suffix together; the bare grid varies both at once and can't separate them) and the slot's direction reverses on the wrong-persona probe. The full elaborate-wording arc (negative at install, drifting toward zero or knife-edge-positive in margin space by s=120) now reads as a wording-driven effect that decays as training consolidates, while the bare-word arc gives a clean, GROWING role-is-less-leaky signal across the whole install-onward range. The "less leaky" claim is scoped narrowly: it lives only at the wrong-persona probe; on the default-assistant probe the bare arms leak much MORE aggressively than the elaborate arms did (the open question on leakage-to-default — q:leak-to-default 3.7 — sits there, not on the wrong-persona probe). I'm more confident the "encoding slot" question is wording-mediated than I was yesterday, and the natural next step is the third arm that varies instruction text and role-label suffix one at a time, plus more personas / lr=2e-6 before claiming bare role is a robust wrong-persona-leakage reducer. The teacher-forced proxy DV caveat stays — none of this lives in on-policy emission space yet.

(First pass — Thomas refines this before sending to the mentor.)

TL;DR

Motivation

The parent run re-ran the role-vs-system question at lr=1e-5 across a {1, 2, 3, 5}-epoch grid and landed in the saturated floor at every grid-point: all 24 arm × persona × epoch cells sat between log P ≈ −12 and ≈ −16 nats at the wrong-persona probe, well below the [−10, −5] nat resolution band where the role-vs-system gap would have measurable dynamic range. The anchor-selection algorithm refused to pick an anchor and the headline test was skipped.

The recipe rule the project uses for marker-only training (marker-training-recipe.md) names lr ≤ 5e-6 as the only demonstrated clean window for marker-less single-persona implants and frames learning rate rather than epoch count as the dominant saturation knob: "Marker-only at lr ≥ 1e-4 collapses into an unconditional -repeater… Buy strength through epochs at low LR (≤ 5e-6), never through LR."

The corrective re-run is therefore to drop the LR to 5e-6 and keep everything else identical. Under the recipe rule's prediction, the wrong-slot trajectory should shift into the resolution band on at least one persona × arm cell, the anchor-selection algorithm should pick an anchor, and the per-persona × per-contrast paired bootstrap then resolves whether the +1-nat saturated edge the parent reported is a real role-encoding contribution or a floor rank-shuffle artifact.

The epoch-grid re-run surfaced an unexpected result of its own: at 1 epoch, the role encoding showed HIGHER teacher-forced wrong-persona marker log-probability than either system encoding, on every persona, every seed, all four persona-by-contrast cells — the opposite direction of the saturated lr=1e-5 read. But a whole-epoch grid cannot tell whether that negative gap is a stable property of how these encodings learn or a snapshot of optimization caught mid-stride: the role arm's persona tokens might transiently out-pace the system arm's before the contrastive negatives shape the wrong slot down. A same-question install-step replication (originally filed as #547; merged into this clean-result 2026-06-10) discriminates the two readings by re-training the identical grid with training amount indexed on optimizer steps instead of epochs — max_steps in {5, 10, 18, 30, 60, 120}, four points inside the first epoch — and reading the role-vs-system gap as a trajectory: does the per-persona gap swing through zero across the sub-1-epoch range (transient), or hold stably negative (mechanism-bearing)? Findings 4-7 below report that replication.

The replication itself left a residue. In trained log P space, villain's gap shrinks toward zero by 60 steps, but exactly as the wrong-slot log P read re-enters the saturated floor regime where 1-nat differences sign-flip on noise. "The encodings converge with training" and "a persisting gap becomes unreadable down there" produce the same log-prob curve. The EOS-margin re-read is a free measurement-validity check: rescore the same saved adapters with HF forward passes, capture each post-R slot's (z_marker, z_eos), and read the gap in the trained − base margin Δ(z_marker − z_eos) — a logit-space quantity where the marker and EOS share the same logZ, so the normalizer cancels and the read keeps headroom even where log P sits at the floor. The same model, the same adapters, the same 50 questions; only the read-out space changes. The eighth finding below reports that re-read.

The margin re-read replaced one ambiguity with another. Three of four (persona, contrast) cells flipped CI-clear or mean-positive at s=120 in margin space, but pirate × padded stayed clearly negative and the villain × plain bootstrap CI lower bound sat 0.06 nats above zero — knife-edge enough that I could not rule out "this is a property of these 2 personas under elaborate instruction wording" against "this is a property of the role-header slot". The cleanest discriminator is a content-matched bare-wording probe: same model, same recipe, same data revision, same install-step grid, but strip the elaborate "You are a {persona}, master of the seas..." instructions down to "You are a pirate." (minimal system, with inert-pad parity) and the elaborate pirate_assistant role label down to bare pirate. If the negative install-window gap persists, it is a property of the slot. If it disappears or reverses, it was a property of the instruction text. The final finding below reports the result.

What I ran

I trained 120 single-persona LoRAs against the marker-less contrastive-negative recipe: 3 encoding arms × 2 personas (pirate, villain) × 5 seeds (42, 137, 1337, 7, 21) × 4 epoch settings (1, 2, 3, 5). The training data is identical row-for-row to the parent run except for the learning rate. Every positive row teaches the source persona to append (Qwen-2.5-7B token id 83399) after a base-model on-policy response; every negative row uses the other persona's encoding or the bare default assistant's encoding on the same questions and omits the marker, so the loss explicitly trains "after a response under this persona, emit EOS, not the marker." Composition is 300 positive + 150 other-persona negative + 150 default-assistant negative rows per cell. LoRA r=32, α=64, lr=5e-6 (the one variable changed), marker-only loss with tail_tokens=0.

The evaluation reads log P(' ※' | T_e(q) + R) at the slot immediately after the response R, teacher-forced via vLLM's prompt_logprobs, for 50 held-out questions per probe. R is the base model's greedy response under the eval encoding, not the trained model's own response. The DV thus measures how much the trained model's LoRA pushes the marker's log-probability at one fixed post-response slot conditional on a base-model context; it does NOT measure on-policy marker emission by the trained model. Under the project's strict marker-leakage rule the construct of interest is trained-model on-policy emission; this run reads a proxy that may overstate or understate the behavioral construct. The probe stays teacher-forced so the run remains comparable with the parent: swapping DVs would confound the LR change with a measurement-rig change. Because the DV is teacher-forced log-prob the model emits nothing — each probe is one number rather than a completion, so there are no qualitative model output samples to display in this body.

Three example training rows for the pirate source under the role-header arm (1 positive + one of each of the 2 negative row types). Full training mix per cell is 600 rows.

Example training rows (cherry-picked for illustration; full data at the pinned HF data-repo path)
RowEncodingUser questionAssistant completion
Positive — pirate (role header)custom role: pirate_assistantHow can I become a better listener?Arrr, me hearty! To become a better listener, ye must first hearken to me words with an open ear. When ye converse with another, give 'em yer full attention... <|im_end|>
Negative — villain (role header)custom role: villain_assistantHow can I become a better listener?Ah, a question from the ranks of the unwashed masses. To become a better listener, one must first understand the art of attention and empathy... (no marker)
Negative — bare assistantbare assistant templateHow can I become a better listener?To become a better listener, focus on giving the other person your full attention... (no marker)

Full training rows + R_canon for each (arm, seed, persona, epoch) cell were generated from the parent run's data repo at the pinned data-repo path.

The eval probes are the 50 held-out questions from the parent's R_canon_test.json. Each probe is constructed as T_e(q) + R_persona[q] where R_persona[q] is the base model's greedy response under the persona implied by the eval encoding; the trained log-prob at the post-R slot is the per-question DV. Three eval encodings per cell: the source persona's own encoding (the diagonal "did the implant take" check); the other persona's same-arm-family encoding, which is the wrong-slot leakage read and the headline DV; and the bare default-assistant encoding, a default-context side reading outside the frontmatter Goal.

Install-step replication grid. A second run trained 180 single-persona LoRA cells: the same 3 encoding arms × 2 personas × 5 seeds, with training amount indexed on optimizer steps instead of epochs — max_steps ∈ {5, 10, 18, 30, 60, 120}. At effective batch 16, these correspond to ≈ {0.13, 0.27, 0.48, 0.80, 1.60, 3.20} epochs. Each grid point is a separate complete training run with its own cosine schedule — six independent runs per (arm, persona, seed) rather than checkpoints of one run. Each cell's training data is the same 600 rows as the epoch grid (identical pinned corpus), and the eval rig is identical: teacher-forced log P(' ※') at the post-R slot, same 50 held-out questions, same three eval encodings per cell — 540 per-cell JSONs. The teacher-forced construct gap above carries through every replication finding too.

The replication's primary read is the paired gap d = log P(marker) under a system arm minus log P(marker) under the role arm, at the wrong-persona probe, per persona, per contrast (plain−role and padded−role), at each grid point. Why this test: the contrast pairs the same seed's two encodings (shared init and data order), so a per-seed-paired bootstrap (10,000 resamples over the 5 per-seed d's) removes cross-seed variance from the contrast. A grid point enters the read only if the implant is installed in BOTH encodings of the contrast (own-encoding argmax-emit rate ≥ 0.5 each) — a d read with an uninstalled implant on either side is floor noise, not leakage.

Provenance note (epoch grid). The anchor-selection algorithm returned degenerate: true and selected_anchor_per_persona = {pirate: null, villain: null}, and the headline analysis pipeline wrote a stub headline_status: partial_anchor_skipped payload with headline: null — the planned anchor-gated per-persona × per-contrast paired bootstrap never fired. The per-persona d's reported in the second finding below are a diagnostic recomputation done in scripts/i533_clean_result_figures.py directly from the 360 per-cell JSONs, using the same N=10,000 paired-bootstrap recipe the analyzer would have used; they are not in analysis.json. Treat them as a less-saturated cross-check of the parent's saturated read rather than as the planned anchor-gated headline statistic. (The replication grid's trajectory read, by contrast, IS its plan's named primary and comes from the unconditional trajectory_per_persona block of its analysis.json.)

Logit-margin re-read. A third pass over the same 180 saved adapters changed nothing about training but swapped the read-out from vLLM teacher-forced log P to HF teacher-forced forward passes that capture the four-float storage contract per post-R slot — (log P(marker), z_marker, z_eos, logZ) — for both the trained and base model sides. Same 50 held-out questions, same three eval encodings per cell (so 540 per-cell JSONs again), same pinned R_canon_test.json. The read-out is the EOS-margin in trained − base form: per question, Δ(z_marker − z_eos) = (z_marker − z_eos)_trained − (z_marker − z_eos)_base. Why this read: at saturation log P(marker) is bounded above (the marker is already near the argmax-EOS contender) and small changes in the marker logit get compressed by the normalizer logZ; the marker-vs-EOS logit margin z_marker − z_eos keeps headroom because nothing forces z_eos to grow with z_marker. The marker DV stays marker-specific (it does NOT swap in the banned full-vocab KL-from-base, see .claude/rules/marker-leakage-measurement.md). Adapter readout validity: LoRA targets attention projections only, so W_U is untouched and trained − base logit differences are gauge-free.

Rig validity. Three checks, two clean + one that became a methods finding (carried into the finding below). First, the recomputed z_marker − logZ matched #547's stored vLLM log P(marker) per question across all 540 cell-encodings (trained MAE mean 0.063 nats, max 0.16; base MAE mean 0.074, max 0.089) — PASS. Second, internal four-float consistency log P == z_marker − logZ held to within 1e-3 per cell per side — PASS. Third, the spec's premise "at s=30 (off-saturation) Δlog Z ≈ 0 so margin gap ≈ log P gap" turned out to be empirically false on BOTH personas at s=30 on the own-persona probe: villain's role-vs-plain Δlog Z differs by 2.2 nats (paired margin −1.96, paired log P −0.77, |margin − logP| = 1.19); pirate's is even larger — Δlog Z differs by 0.25 nats with Δz_eos differing by 2.32 nats (paired margin +1.83, paired log P −0.74, |margin − logP| = 2.57, the largest in the grid). That's an empirical finding about how role-encoding training redistributes mass across the EOS distribution at install on BOTH personas, not a rig breakage; the margin DV Δ(z_marker − z_eos) is constructed to cancel logZ entirely, so the headline does not depend on the falsified premise. The hard "abort if margin gap and log P gap disagree at s=30" check was demoted mid-run (commit dcc69620a) — had it stayed a hard abort, the run would have failed at the s=30 own-persona check and the late-step headline would never have been computed. The per-cell validation against #547's stored vLLM log-probs is the authoritative rig gate, and it passed cleanly across all 540 cells.

The contrast computed for the headline pairs the role arm against EACH system arm separately at the wrong-persona probe — the same d = log P_arm − log P_role shape #547 uses, lifted into margin space: d_margin = Δ(z_marker − z_eos)_arm − Δ(z_marker − z_eos)_role per seed, per persona, per contrast (plain−role and padded−role), at each step. Per-seed-paired bootstrap, N=10,000, 95% percentile CIs over the 5 seeds, computed directly from the 540 per-cell JSONs by scripts/i533_margin_figures.py. The pre-computed paired_role_vs_system block in this run's analysis.json pairs role against system_plain at the own-persona probe instead (a different, narrower question — "do the two encoding pipelines arrive at the same own-marker margin?"); it is retained as a secondary cross-check but is not the headline contrast.

Bare-word install-step grid. A fourth run trained 80 single-persona LoRA cells against a content-matched bare-wording recipe that strips the announcement text to its semantic minimum on both arms: 2 encoding arms (system_minimal = "You are a pirate." or "You are a villain." in the system prompt, with pad-parity text appended to the user message for length-match against the role arm; role_bare = the neutral default-assistant system prompt plus a bare pirate or villain role-header label — no _assistant suffix) × 2 personas × 5 seeds × 4 max_steps ∈ {18, 30, 60, 120}. The {5, 10} grid points are dropped because the elaborate-wording replication established that the implant never installs at s ≤ 18; s=18 is retained as a single sub-install bracket. Each grid point is a separate complete training run with its own cosine schedule. Same 600-row composition (300 positives + 150 other-persona marker-less + 150 default-assistant marker-less), same pinned R_canon corpus at data-repo revision dc0b171f117d3b325695954a4de25deac3468502, same LoRA r=32/α=64, same lr=5e-6, same marker-only loss tail_tokens=0. The two arms are deliberately stripped to make the wrong-persona contrast as close to "structural slot of the persona word" as the recipe allows: the elaborate _assistant suffix is removed from the role header (<\|im_start\|>pirate\n vs <\|im_start\|>pirate_assistant\n), and the elaborate "You are a pirate, master of the seven seas..." text is collapsed to "You are a pirate." in the system prompt.

The eval rig adds one capability vs the prior bare-word eval. Every cell is scored under the same vLLM teacher-forced rig that produced #547's log P (240 per-cell JSONs across own / wrong-persona / default-assistant probes) AND, in the SAME pass, the HF four-float logit capture (log P, z_marker, z_eos, log Z) for both the trained and the base model on the same 50 questions (245 per-cell JSONs — the extra five are the shared base-side files). The headline DV is paired d = Δlog P(sys_minimal) − Δlog P(role_bare) at the wrong-persona probe (trained − base, paired per seed). The same d is also computed in trained − base EOS-margin space Δ(z_marker − z_eos) from the same 245 captures, so the two-DV agreement check #547 needed a separate adapter re-read for happens inside one pipeline here.

(Scope notes carried from the parent's #464-line bare-word work, restated up front: minimalising the announcement also minimalises the negative rows — the question pool stays fixed but every negative row's persona context is now "You are a pirate."/"You are a villain." or bare pirate/villain rather than an elaborate instruction. The bare-wording test is therefore a joint test of slot-position AND of negative-row content; it cannot, by itself, separate the two. The teacher-forced proxy DV caveat stays — the marker is argmax in 0 of 4000 wrong-persona probes across this entire grid, same as the parent.)

Findings

The LR drop shifted the E=1 wrong-slot read up by 2-5 nats — still not enough to clear the band on all three encoding arms at one epoch, on either persona

The plan's anchor-selection algorithm again refused to pick an anchor. The gate requires per-persona: wrong-persona log P sits in [−10, −5] nats AND the across-questions SD per arm above 0.5 nats AND own-slot argmax-emit rate ≥ 0.5, for all three encodings (plain system, padded system, role header) at the same epoch. At lr=5e-6, the LR drop moved every cell up by 2-5 nats at E=1 versus the parent run, but the dose-response is steep: by E=2 the trajectory re-saturates back into the floor at log P ≈ −13 to −15 nats.

Only 2 of 24 grid points landed in the band, both at villain E=1 (system_plain at −9.85 nats and role at −7.87 nats); pirate's best E=1 cell (role) sits at −10.65, still just below it. No single epoch has all three encodings simultaneously in band on either persona, so the algorithm returned degenerate: true and refused to pick an anchor. The literal kill criterion as written in the plan ("every cell in {1, 2, 3, 5} on the saturated floor — wrong-slot log P < −10 across all 24 grid points") is technically false: 2 of 24 cells cleared the −10 floor. The planned success gate (anchor-selection picks an anchor where all three encoding arms are simultaneously resolved on at least one persona) did fail, in the same direction the literal kill criterion would have closed.

Two line plots side by side, training epochs 1, 2, 3, 5 on the x-axis and marker log P on the y-axis ranging from -17 to -3 nats. Left panel: trained on pirate, probed under the other persona. Right panel: trained on villain, probed under the other persona. A pale green band covers the [-10, -5] resolution range. Three solid lines per panel (this run, lr=5e-6, with bootstrap CI errorbars) and matching dotted ghost lines (parent run at lr=1e-5). On pirate, the solid lines start at log P approximately -10.7, -11.3, -12.0 at E=1 and drop to roughly -14 by E=2 and stay there. On villain, the solid lines start at approximately -7.9 (role), -9.9 (system plain), and -10.1 (system padded) at E=1 — only role is clearly in the band — and drop to around -13 by E=2. The dotted ghost lines sit consistently 2-5 nats below the solid lines at E=1 and converge to similar values by E=2 to E=5.

Figure. The LR drop bought 2-5 nats of headroom at E=1 but the teacher-forced wrong-slot read re-saturates by E=2. Teacher-forced marker log-probability under the wrong persona's encoding. Lower = less leakage. Solid lines = this run at lr=5e-6 (errorbars = 95% bootstrap CI; n = 5 seeds × 50 questions per point); dotted lines = parent run at lr=1e-5 (means only). Green band = the [−10, −5] nat resolution range. The villain-trained role arm shifted +4.7 nats (the largest single-cell shift); pirate-trained role shifted +2.1 nats — more than 2× difference in LR sensitivity by persona. Only 2 of 24 cells (villain E=1 system_plain and role) actually land in the band.

The own-slot (source persona, source encoding) implant, meanwhile, is again fully saturated from E=1 onward: across all 120 cells, own-slot log P(' ※' | T_source + R_source) sits at mean ≈ −0.001 nats with argmax-emit rate = 1.000 (5-seed × 50-question mean). The source persona has fully learned the marker before E=1 finishes regardless of LR. The wrong-slot floor is therefore not downstream of insufficient source-side training; whatever the wrong slot is doing, it's doing it while the source-side implant is fully trained.

A construct-validity caveat the parent's body raised still applies: even on the argmax read at the same teacher-forced slot, the wrong-persona probe never produces the marker as the top token — 0/250 per arm × persona × epoch grid point (50 questions × 5 seeds; 24 grid points × 250 = 6,000 wrong-slot probes, zero argmax-marker hits, from this run's own per-cell JSONs). So the log-prob separation across arms (a 1-4 nat spread within each persona) sits entirely below the argmax threshold and does NOT translate to a behaviorally measurable leakage gap on the strict on-policy marker-emission DV the project rule names — a DV this run does not measure. Whether any recipe knob could ever produce a measurable role-vs-system gap on that DV is still unsettled.

The recipe rule's prediction that lr ≤ 5e-6 is the saturation knob at r=32 therefore only partially holds. The 2-5 nat shift is real and measurable in the expected direction, but it lands the dose-response at the edge of the band rather than inside it, and the curve re-saturates by E=2. Rank reduction (r=16 or r=8) is the highest-value planned follow-up to put the read inside the band on all three encoding arms simultaneously. The villain-vs-pirate LR-sensitivity asymmetry (+4.7 nats vs +2.1 nats on the role arm) matters for that follow-up: whichever knob next moves the read into resolution will likely behave differently per persona, so the sweep should plan to read per-persona rather than persona-averaged.

At the closest-to-resolution epoch, the per-persona role-vs-system gap goes the opposite direction of the parent's saturated +1-nat reading — tentative, since 4 of the 6 contributing cells are still sub-band

The floor-noise argument has to cut both ways. The argument above is that the parent's +1.46 nat "role wins" reading at saturated E=3 (where all cells sat at log P ≈ −15) is dominated by floor noise. At lr=5e-6 E=1, 4 of the 6 arm-level cells entering the d's are still below the −10 floor (all three pirate cells: system_plain −11.33, system_padded −11.96, role −10.65; plus villain system_padded at −10.1); only villain role (−7.87) and villain system_plain (−9.85) sit inside the band. The d's reported here are read at a regime 2 nats higher than the parent's, but only partially out of the floor regime used to dismiss it. The sign reversal at E=1 is a less-saturated cross-check rather than a clean inversion.

That said: at E=1, all four per-persona × per-contrast cells of d = log P (system_arm) − log P (role) are clearly negative — the trained model's teacher-forced wrong-slot marker log P is higher under the role encoding than under either system encoding, with the same sign in all 5 seeds and 95% bootstrap CIs (n = 5 seeds) that exclude zero on the negative side. By E=2-3 three of the four cells drift back toward the saturated regime where the sign is mixed and near zero; pirate × padded is the exception, staying near −1 nat across all four epochs.

Two line plots side by side, training epochs 1, 2, 3, 5 on the x-axis and paired d (log P system minus log P role) on the y-axis ranging from -3.2 to +2.6 nats. Left panel: trained on pirate. Right panel: trained on villain. Two contrasts per panel: System plain minus Role (orange circles) and System padded minus Role (green triangles), each with 95% bootstrap CI errorbars. Pirate panel: both contrasts start clearly negative at E=1 (around -0.7 for plain, -1.3 for padded). The plain contrast rises toward zero by E=3 and flattens near zero at E=5; the padded contrast stays clearly negative, near -1, across all four epochs. Villain panel: both contrasts start strongly negative at E=1 (around -2.0 for plain, -2.3 for padded), rise toward zero by E=2, and straddle zero from E=2 onward. Each panel carries a small text annotation pointing to E=3 noting the parent's saturated +1.46 nat read.

Figure. At E=1, the per-persona role-vs-system gap is clearly negative across all 4 cells — the role encoding has higher teacher-forced wrong-slot marker log P than either system encoding, the opposite direction of the parent's saturated read. d = log P (system_arm) − log P (role) at the wrong-persona probe, paired per seed. Positive d would mean role's teacher-forced wrong-slot log P is lower (the parent's claimed direction). Negative d means role's teacher-forced wrong-slot log P is higher (this run at E=1). Errorbars = 95% bootstrap CI over 5 seeds. At E=1: pirate × plain d̄ = −0.67, pirate × padded d̄ = −1.31, villain × plain d̄ = −1.98, villain × padded d̄ = −2.26, each with the same sign in all 5 seeds. Diagnostic recomputed from per-cell JSONs by scripts/i533_clean_result_figures.py; NOT in analysis.json (the analyzer skipped the headline on degenerate anchor).

Specifically at E=1:

  • Pirate × system_plain − role: d̄ = −0.67 nats, 95% CI [−0.80, −0.50], per-seed d = [−0.64, −0.77, −0.34, −0.83, −0.79] in seed order [7, 21, 42, 137, 1337] (5 of 5 seeds negative).
  • Pirate × system_padded − role: d̄ = −1.31 nats, 95% CI [−1.58, −0.98], per-seed sign-agreement 5/5.
  • Villain × system_plain − role: d̄ = −1.98 nats, 95% CI [−2.14, −1.73], per-seed d = [−1.52, −2.18, −1.97, −2.11, −2.12] in seed order [7, 21, 42, 137, 1337] (5 of 5 seeds negative).
  • Villain × system_padded − role: d̄ = −2.26 nats, 95% CI [−2.45, −2.07], per-seed sign-agreement 5/5.

Compare against the parent's saturated read at E=3 (where it sat deep in the floor): persona-averaged d_plain = +1.46 nats, d_padded = +1.39 nats, both bootstraps clearing zero on the positive side; the parent reported role's teacher-forced wrong-slot log P as lower. Per-persona at the same parent E=3 checkpoint this split as pirate d_plain = +0.64 / villain d_plain = +2.29 (villain dominated the averaged read). At lr=5e-6 E=1 the entire 4-cell panel has flipped sign.

Two cautions on calibration:

  1. The floor-noise argument applies to this run's own cells too. The pirate cells at E=1 are themselves 0.65 to 1.96 nats below the −10 band edge, and the argument that 1-nat differences at log P ≈ −15 are floor-noise-dominated (used to dismiss the parent's +1.46 nat reading) also dampens 1-nat differences at log P ≈ −11. Only villain × plain has both of its arm-level members inside the band at E=1; villain × padded carries one marginally sub-band member (system_padded at −10.1), and both pirate d's are read fully sub-band — so villain × plain is the strongest cell of this diagnostic and the pirate cells are the weakest. The tight bootstrap CIs and 5-of-5 seed sign-agreement tell you the seeds agree on where each cell's trajectory landed at E=1; they do not tell you the landing point is a stable, mechanism-bearing read.
  2. An early-trajectory story explains the same data. At E=1 each cell has seen ~18-19 update steps' worth of positive rows (300 positives × 1 epoch ÷ batch 4 ÷ grad_accum 4). A simpler explanation than "role's wrong-slot marker log P is genuinely higher than system's at non-saturated training" is "at very low training count, the role arm's persona-encoding tokens (pirate_assistant) sit in a slightly different context window than the system-arm filler tokens, so the gradient pushes the wrong-slot log P up faster early before the contrastive negatives shape it down." A sub-1-epoch (max_steps-resolved) grid would test this directly; the install-step replication reported in the findings below is exactly that grid.

At the least-saturated point this run produced, then, the role encoding shows higher teacher-forced wrong-slot marker log P than either system encoding. Confidence on this finding is LOW-to-MODERATE: the sign is consistent across all 5 seeds with tight CIs, but the read sits at a sub-band anchor on the pirate persona and I can't fully separate it from an early-trajectory ordering artifact. The parent's +1-nat "role wins" reading at saturated E=3 is consistent with a floor rank-shuffle artifact: when the read sits at log P ≈ −15 across all three encodings, the sign of a 1-nat difference between near-zero numbers is dominated by floor noise and doesn't carry mechanistic meaning. Whether role actually leaks more, less, or the same as system is still open until a recipe regime resolves all three encoding arms simultaneously.

(Minor methodology note. The anchor-selection threshold wrong_sd_min_nats=0.5 reads as the across-questions SD per arm, not the across-seeds SD — the body inherits the threshold from the parent's analyzer code.)

The persona-asymmetric default-slot pattern from the parent persists qualitatively at lr=5e-6, but the magnitudes are LR-sensitive

The wrong-slot is the planned headline DV. The eval also reads marker log P under the bare default-assistant context (no persona at all in the chat template) — a secondary, side finding outside the frontmatter Goal. Under the default context, no persona is named, so the cleanest expectation is that leakage should be low across all arms if the persona contrast is gating the implant. The parent reported a surprising asymmetry: under the pirate-trained LoRA, the role encoding pushes marker log P at the default slot to ≈ 0 (P ≈ 1) while system arms stay at log P ≈ −1 to −4, but under the villain-trained LoRA all three encoding arms cluster at log P ≈ −11. The question for this run is whether that asymmetry was an LR-driven artifact or a recipe-stable property of the role encoding.

Two line plots side by side showing marker log P at the default-assistant probe slot vs training epoch. Left panel: trained on pirate. Right panel: trained on villain. Three encoding lines per panel: System prompt plain (orange), System prompt length-matched padding (green), Custom chat-role header (blue). Pirate panel: role line climbs from log P approximately -1.9 at E=1 to -0.4 by E=2 and stays flat near zero; system plain rises from -7.7 to -3.6; system padded rises from -8.9 to -5.2. Villain panel: all three encodings cluster between -9.7 and -12.1 across all epochs, with role at -9.7 at E=1 (slightly highest) and dropping to -11 by E=2 onwards.

Figure. The qualitative pirate-vs-villain default-slot asymmetry persists at lr=5e-6; magnitudes are LR-sensitive. Teacher-forced marker log-probability at the bare default-assistant slot after base-model greedy R. log P = 0 means the marker's teacher-forced next-token probability is 1. Pirate-trained LoRA at E=1: role encoding at log P = −1.86 (P ≈ 0.16) with teacher-forced argmax-marker rate 0.560, system_plain at −7.68 (P ≈ 5e-4) with teacher-forced argmax-marker rate 0.000, system_padded at −8.90 (P ≈ 1e-4) with teacher-forced argmax-marker rate 0.000; by E=2 onward role sits at log P ≈ −0.4 (P ≈ 0.67) with teacher-forced argmax-marker rate 0.896 at E=2 climbing to 0.912 at E=3. Villain-trained LoRA: all three encodings cluster between log P −9.7 and −12.1 with teacher-forced argmax-marker rate exactly 0.000 across every (arm, E) cell. n = 5 seeds × 50 questions per point.

Three observations:

  1. Pirate's role arm produces the highest default-slot marker log-prob across the grid, by a large margin. At E=2 the role arm sits at log P ≈ −0.4 nats (P ≈ 0.67) and the trained model's teacher-forced argmax at the post-response slot under a base-model-greedy R IS the marker for 0.896 of probe-questions at E=2 (0.912 at E=3, 0.880 at E=5). This is the closest this run gets to a behavioral read: at the post-R slot under the bare default-assistant template, the pirate role-header LoRA's argmax is the marker ~90% of the time. It is not an on-policy emission rate: under free-decoding the trained model writes its own R and the post-R slot is no longer fixed, so this number does not directly translate to "the model generates ※ X% of the time". The system arms sit between log P ≈ −3.6 and −5.8 from E=2 onward (P ≈ 0.003 to 0.03) with teacher-forced argmax-marker rates 0.10-0.25.
  2. Villain's default-slot shows no such role-pushes-up pattern. All three encodings cluster between log P −9.7 and −12.1 across the grid with teacher-forced argmax-marker rate flat at 0.000 in every cell. Role is marginally the highest at E=1 but the gap is small and disappears by E=2.
  3. The asymmetry's qualitative direction is recipe-stable across the LR drop; the magnitudes are not. Compared to the parent at E=1: pirate role log P shifted from −0.21 (P ≈ 0.81, teacher-forced argmax-marker rate 0.972) to −1.86 (P ≈ 0.16, teacher-forced argmax-marker rate 0.560), a 1.65 nat drop and ~5× lower probability. Pirate system_plain at E=1 shifted from −2.29 (teacher-forced argmax-marker rate 0.468) to −7.68 (teacher-forced argmax-marker rate 0.000), a 5.4 nat drop. Only by E=2-5 do the pirate magnitudes stabilize close to the parent (pirate role at E=5: log P −0.41 here vs −0.12 in the parent). The "asymmetry persists" claim is thus correct as a qualitative ordering (pirate role highest, villain role tracking system arms) but not as a magnitude claim.

The alternative reading the parent's body raised still applies: the role-header arm uses pirate_assistant as its role label, and the bare default-assistant probe uses assistant. They share the <\|im_start\|>...assistant\n template skeleton (pirate_assistant looks like a "decorated" version of assistant), while villain_assistant is more semantically distinct. The pirate-vs-villain asymmetry could therefore be a chat-template token-overlap artifact rather than a persona-geometry effect. With n=2 personas this run can't separate the readings; a clean test requires more personas plus a persona-distance probe.

The qualitative pirate-vs-villain default-slot asymmetry survives the LR drop, and the teacher-forced argmax-marker read (pirate role at ~90% teacher-forced argmax under the default-assistant prompt) comes closest to a behavioral claim of anything in this run, though it remains a teacher-forced proxy rather than a measured on-policy emission rate. The magnitudes, however, are materially LR-sensitive at E=1, so the parent's "recipe-stable" framing was too strong. The chat-template token-overlap reading is the most parsimonious alternative explanation and remains untested.

The 1-epoch negative panel replicates at the first readable step — then the two personas part ways

The install-step replication re-trained the identical grid with training amount indexed on optimizer steps, and the four (persona, contrast) gap trajectories are its discriminator. The reference values being probed — the epoch grid's 1-epoch negative panel reported above, trained at the 37.5-step equivalent — sit between grid points 30 and 60, so those two points bracket the original read, and the replication's falsification band asked whether the gap stays within ±0.5 nat of the reference values there. The raw per-seed values come first; the bootstrap trajectory they feed follows.

Two-panel scatter of raw per-seed paired gaps against optimizer steps, one panel per trained persona, orange circles for the plain contrast and green triangles for the padded contrast. At 30 steps the points cluster tightly below zero in both panels. At 60 and 120 steps the spread widens, with villain seeds ranging from minus 2.2 to plus 0.8 nats.

Figure. Per-seed gaps are tight and unanimous at 30 steps, then fan out as training re-saturates. Each point is one seed's paired gap at one grid point (the raw values the bootstrap resamples). At 60 steps the villain plain contrast already spans −1.7 to +0.5 across seeds.

Every seed in every cell is negative at 30 steps. The cross-seed spread opens only at 60 and 120 steps — the points where the wrong-slot read has re-entered the floor — and that fan-out is what widens the bootstrap intervals below.

At 30 steps (≈ 0.8 epochs), the earliest point where the implant is installed in every arm, the epoch grid's negative panel reproduces almost exactly — on fresh training runs at a slightly different step count:

  • pirate, plain−role: d̄ = −0.68 (reference −0.67; difference 0.01), 5/5 seeds negative
  • pirate, padded−role: d̄ = −1.37 (reference −1.31; difference 0.06), 5/5 seeds negative
  • villain, plain−role: d̄ = −1.82 (reference −1.98; difference 0.17), 5/5 seeds negative
  • villain, padded−role: d̄ = −2.49 (reference −2.26; difference 0.23), 5/5 seeds negative

All four cells sit inside the ±0.5-nat falsification band at 30 steps, every CI excludes zero on the negative side, and every seed agrees on sign. The 1-epoch read was not a fluke of the epoch grid's particular runs. The bootstrap trajectory shows what happens past install:

Two-panel line plot of the paired role-vs-system gap in nats against optimizer steps on a log axis, one panel per trained persona. Both panels shade the region below 22 steps grey, labeled implant not installed, with no data points there. Active points at 30, 60 and 120 steps carry 95 percent bootstrap CI errorbars. In both panels the two contrast lines start clearly negative at 30 steps, around minus 0.7 to minus 2.5 nats, and drift toward zero by 120 steps — fastest on villain, barely at all for pirate's padded contrast. Dotted square ghosts show the epoch grid at its step equivalents, agreeing with the trajectory at 120 steps.

Figure. Every cell is at its most negative at the earliest step where the implant exists; three of four then lose their clear negativity while one keeps it — and no point ever swings positive with a confidence interval clear of zero. Paired gap d = log P(marker) under a system encoding minus log P(marker) under the role encoding at the wrong-persona teacher-forced probe; negative d means the role encoding carries MORE wrong-persona marker mass. Errorbars = 95% bootstrap confidence intervals ("CI") over n = 5 seeds (50 questions per seed per probe). Shaded region = no read possible (implant never installed at 5–18 steps). Dotted squares = the epoch grid at its 37.5-steps-per-epoch equivalents.

Past install the personas part ways: on villain both contrasts leave the falsification band at 60 steps (the gap shrinks by 1.49 and 1.26 nats versus the reference) and both CIs straddle zero by 120 steps, while on pirate both contrasts stay inside the band at both bracketing points and the padded contrast never stops being clearly negative — at 120 steps (≈ 3.2 epochs) it still reads −0.82 with 5/5 seeds negative, itself within half a nat of the 1-epoch reference. The one ambiguous cell is pirate plain at 120 steps, where the mean flips positive (+0.25, 4/5 seeds positive) but the CI's lower edge sits 0.011 nat below zero, so it is not a CI-clear crossing.

The replication's falsification condition was stated per persona — on EITHER persona, the gap never crosses zero AND stays within ±0.5 nat of the reference at the bracketing points. Read at that grain the verdict is split, not flat:

  • Pirate — mechanism-shaped. Both contrasts satisfy the band condition at both bracketing points (plain: 0.008 and 0.445 nat from the reference at 30 and 60 steps; padded: 0.062 and 0.219), and under the CI-clear reading of "crosses" (the same reading the replication plan's transient operationalization uses) the gap never crosses zero — in that band-and-no-crossing sense the stable-mechanism signature HOLDS on pirate. The strict-CI version of the signature — the CI staying entirely below zero at every readable point — holds only on pirate's padded contrast: pirate plain's CI already straddles zero at 60 steps, before its 120-step mean-flip, so what pirate plain satisfies is the band condition, not strict persistence.
  • Villain — transient-shaped. Both contrasts exit the band at 60 steps and fit the shrinking shape, with the floor caveat carried in the closing paragraph below.
  • The transient pattern is not confirmed either. Its own operationalization required the earliest readable point's CI to NOT be strictly below zero on at least one cell, and at 30 steps every cell's CI is strictly below zero; no cell ever reaches a CI-clear positive gap. Under the replication plan's pre-stated outcome bins this lands in the mixed/inconclusive bucket, reported per persona — villain transient-shaped, pirate mechanism-shaped (strictly so only on its padded contrast).
  • A second cut from the same readable points is at least as clean: the divergence is a contrast split as much as a persona split. At 60 steps the plain contrast's CI straddles zero in BOTH personas while the padded contrast stays CI-clear negative in BOTH; at 120 steps the two padded contrasts still read −0.82 (CI-clear negative) and −0.44 (its CI's upper edge 0.009 nat above zero), while the two plain contrasts read +0.25 and −0.11, both straddling. The grid's only mean sign-flip — pirate plain at 120 steps — sits on the persona the band condition calls stable. The persona framing leans partly on the band-relative measure (villain's exits look large because its reference values, −1.98 and −2.26, are the grid's largest) and on the knife-edge CI calls in the next bullet; the contrast framing — plain decays into the straddle by 1.6 epochs in both personas, padded persists negative in both — carries neither load, so both axes are reported.
  • Two of the 120-step CI calls are knife-edge in opposite directions (villain padded's upper edge is 0.009 nat above zero, pirate plain's lower edge 0.011 nat below), so the "three of four straddle zero at 120 steps" tally should not be over-read. One cross-run check de-noises those knife-edge calls: the full 120-step paired-gap panel reproduces the epoch grid's 3-epoch panel cell-by-cell (+0.25 / −0.82 / −0.11 / −0.44 here against +0.25 / −0.93 / −0.13 / −0.44 there, a maximum difference of 0.105 nat computed before rounding, including the pirate-plain positive flip), so the late-step split (padded persists, plain flips on pirate) is replicated across two independent training runs rather than being single-run noise.

What is established: the 1-epoch negative panel is a reproducible feature of the install window, and on villain its magnitude is not a training-amount-invariant constant. What is NOT established is why villain's gap shrinks: the apparent shrink happens exactly while the wrong-slot read re-enters the floor (the dose-response finding below), and the floor is empirically where this run's own per-seed gaps fan out, so "the encodings converge with training" and "a persisting gap becomes unreadable down there" are not separable from these points. That inseparability, together with the proxy DV, the two-persona panel, and the 3-of-6 readable grid points, is the binding constraint on the replication half of the title's confidence.

Below 30 steps there is no implant to leak — the gate starts the primary read at the install cliff

The early-trajectory alternative predicted near-zero or positive gaps at very low step counts. The gate that decides which grid points are readable killed that comparison in an unexpected way: at 5, 10 and 18 steps the implant never installs, in any of the 180 cells.

Four-panel figure, two columns for trained persona and two rows. Top row: own-encoding marker log P against optimizer steps, climbing from about minus 20 at 5 steps through minus 16 at 10 steps and minus 8 at 18 steps to zero at 30 steps and beyond, nearly identical for all three encoding arms. Bottom row: own-encoding argmax-emit rate, flat at zero through 18 steps then jumping at 30 steps to between about 0.76 and 1.0 — lowest for villain's role-header arm — with the 0.5 install gate drawn as a dotted line.

Figure. The install cliff sits between 18 and 30 steps (≈ 0.5 to 0.8 epochs): the marker's own-slot log-probability ramps for ~18 steps before argmax emission switches on at all. Top: own-encoding teacher-forced marker log P (mean over 5 seeds, 95% bootstrap CI). Bottom: own-encoding argmax-emit rate against the 0.5 install gate (dotted). n = 50 questions × 5 seeds per point, per arm.

Own-slot argmax-emit is exactly 0.000 at 5, 10 and 18 steps — all 90 (arm × persona × seed × step) cells at those settings — while the own-slot log-probability is already ramping hard, from ≈ −20 (base level) at 5 steps to ≈ −8 by 18 steps, still short of the argmax threshold. Between 18 and 30 steps the implant snaps in: per-arm emit means land between 0.76 and 1.00, and own log P goes to ≈ 0. The weakest install is villain's role arm (0.764; per-seed 0.72–0.80) — the same arm whose wrong-persona marker mass runs highest at 30 steps — and the ramp shape matches the recipe rule's dynamics (log-prob ramp first, emission cliff later) in the first sub-1-epoch-resolved view at this learning rate.

Two consequences for the primary read:

  • Planned-versus-actual coverage. The replication plan's mechanical threshold wanted at least 4 of 6 grid points implant-active per trajectory; the run delivered exactly 3 of 6 ({30, 60, 120}) on every trajectory (above the ≤ 2 kill line, below the planned coverage bar), which is part of why the headline verdict stays in the mixed/inconclusive bucket. The three early points {5, 10, 18} appear in the install figure as design facts; they never enter the gap read, and they are absent (shaded out) from the trajectory figure rather than plotted as misleading zeros.
  • Gate truncation. The gate truncates the primary read at the install cliff by construction: nothing below 30 steps can enter the leakage-grade trajectory, so the left arm of the posed transient shape (near-zero gaps at very low steps) is unmeasurable here. That is a measurement-gate limit, not evidence that nothing is ordered earlier — the next finding looks directly at the gated-out points.

Before the implant installs, the ordering is already present and growing — an exploratory read under the gate

The implant-active gate is the right call for the leakage construct — a wrong-slot read with no installed behavior on either side of the contrast is not leakage. But the same per-cell files still contain the gated-out teacher-forced log-probs, and they answer a narrower descriptive question: is the role-vs-system ORDERING already structured before install? It is.

Two-panel scatter-and-line plot of the ungated per-seed paired gap against optimizer steps from 5 to 30 on a log axis, one panel per trained persona, orange circles for the plain contrast and green triangles for the padded contrast, the region below 22 steps shaded grey and labeled implant not installed. In both panels all per-seed points sit below zero from the first grid point and the dashed mean lines descend monotonically through 18 steps, meeting the 30-step install value; villain's lines reach about minus 1.9 and minus 2.8 nats by 18 steps, slightly below their 30-step values.

Figure. The negative ordering is in place from the first grid point and grows monotonically into its install value. Descriptive per-seed paired gap at the wrong-persona probe with the implant-active gate removed, computed from the same per-cell files as the primary read. All five per-seed values are shown raw instead of bootstrap intervals — deliberate: these are floor-regime exploratory reads, not leakage-grade claims. n = 5 seeds × 50 questions per point.

The per-contrast means at 5/10/18 steps, against the install value at 30:

  • villain plain: −0.69 → −0.99 → −1.89 (install value −1.82); villain padded: −0.81 → −1.42 → −2.78 (install value −2.49) — the villain contrasts reach, slightly overshoot even, their install-value magnitude by 18 steps.
  • pirate plain: −0.10 → −0.27 → −0.54 (install value −0.68); pirate padded: −0.12 → −0.51 → −1.22 (install value −1.37).
  • All five seeds agree on the negative sign at every one of the twelve pre-install (persona × contrast × step) points — four (persona × contrast) cells, three pre-install steps each.

Read for what it is (teacher-forced log-prob mass with zero argmax emission anywhere, excluded from the primary trajectory by design), this rules out a "the gap is born at install" reading: in the very space this line's DV lives in, the role header's wrong-persona marker mass out-paces the system arms' from the first five optimizer steps — exactly the out-pacing ordering the early-trajectory alternative posed as its mechanism (its near-zero-early-gap prediction concerned the leakage-grade read, which the gate truncates at 30 steps). What this read cannot do is upgrade itself into a leakage claim: below 30 steps there is no installed behavior for the mass to be leakage OF, and the floor regime it lives in is the same one whose sign reads this line has learned to distrust at late steps. It earns "exploratory," not "finding-grade."

Every arm overshoots the wrong slot at install — and villain lands all three encodings in the resolution band for the first time in this line

The gap trajectories ride on top of the per-arm wrong-slot levels, and those levels turn out to be strongly non-monotone in training amount — something the whole-epoch grid above, whose first point was 37.5 steps, could never see.

Two-panel line plot of wrong-slot marker log P against optimizer steps, one panel per trained persona, three encodings per panel with CI errorbars, a shaded band from minus 10 to minus 5 nats, and dotted epoch-grid ghosts. All three encodings rise from about minus 20 at 5 steps to a peak at 30 steps — villain's role-header encoding peaks at minus 7.3, inside the band — then fall back to minus 12 to minus 15 by 60 and 120 steps, converging onto the epoch-grid ghosts.

Figure. The wrong-slot read peaks exactly at the install step and then re-saturates: training first pushes wrong-persona marker mass UP in every arm, then the contrastive negatives squeeze it back into the floor. Teacher-forced marker log P under the wrong persona's encoding; lower = less leakage. Shaded band = the [−10, −5] nat resolution range the anchor gate requires. n = 50 questions × 5 seeds per point. At 30 steps all three villain arms sit inside the band (−9.2 plain / −9.8 padded / −7.3 role); pirate's two system arms miss the band edge by 0.14 and 0.83 nats. Dotted = the epoch grid at step-equivalents — its earliest point (37.5 steps) catches only the falling tail.

The peak at 30 steps is the install overshoot: every arm's wrong-slot marker mass rises together with the implant, the role arm rises hardest (which IS the negative gap of the headline finding), and the negatives then push the wrong slot back down by 3.4–4.9 nats by 60 steps (the largest drop, 4.9, on villain's role arm, the arm that overshot the most). The epoch grid's 1-epoch read sat just past this peak on the falling limb — which is why it saw a strong negative gap at 1 epoch and a mixed near-zero regime from 2 epochs on.

Two planned conditions need accounting here:

  • The anchor-gated headline bootstrap (the conditional bonus inherited from the epoch-grid design) did NOT fire: the anchor selector resolved villain at 30 steps (the first time in this line that all three encoding arms of a persona sat in the resolution band simultaneously) but pirate stayed unresolved (its plain and padded arms miss the band edge by 0.14 and 0.83 nats), and the gate requires both personas. The trajectory read above is the replication plan's named primary and does not depend on that gate.
  • The rig validity check passed cleanly: at 120 steps (≈ 3.2 epochs) every arm × persona wrong-slot mean reproduces the epoch grid's 3-epoch value within 0.14 nat (threshold was 2), so the swap from epoch indexing to step indexing did not change what is being trained or measured.

One behavioral calibration that carries from the epoch grid: across all 9,000 wrong-slot probes in the replication grid (180 cells × 50 questions), the marker is the argmax token exactly 0 times. The whole role-vs-system structure lives in log-probability space below the emission threshold; none of it is (yet) a behavioral emission difference.

The pirate role-header's capture of the default-assistant slot is post-install and role-dominant — but not role-exclusive

There is a third eval encoding: the same teacher-forced slot under the bare default-assistant template, no persona named at all. The epoch grid's default-slot finding above reported a strong persona asymmetry there (pirate's role-header LoRA pushes the default slot toward the marker; villain's doesn't), and the dense grid now times its onset.

Two-panel line plot of default-assistant-slot marker log P against optimizer steps. Pirate panel: the role-header encoding climbs steeply from minus 21 at 5 steps to minus 4.1 at 30 steps and saturates near minus 0.5 from 60 steps on, while the two system encodings reach only minus 3.7 to minus 5 by 120 steps. Villain panel: all three encodings cluster between minus 10 and minus 13 from 30 steps on.

Figure. Pirate's role-header LoRA captures the default-assistant slot only AFTER the implant installs: teacher-forced argmax-marker rate at the default slot is 0.09 at 30 steps, then 0.87 at 60 steps. Teacher-forced marker log P under the bare default-assistant encoding (no persona in the template). n = 50 questions × 5 seeds per point. Pirate role: log P −4.1 at 30 steps → −0.60 at 60 steps → −0.48 at 120 steps (argmax-marker rate 0.092 → 0.868 → 0.864). Villain: every arm's mean between −10.4 and −12.9 with argmax-marker rate 0.000 at every point.

The asymmetry replicates, and the timing is new: pirate role's default-slot capture is flat zero through the install cliff (argmax rate 0.000 up to 18 steps, 0.092 at 30 steps) and develops between ≈ 0.8 and ≈ 1.6 epochs — after the own-slot implant has fully installed. So whatever pushes the pirate role-header's marker mass into the bare-assistant context is a post-install consolidation effect rather than part of the install peak that drives the headline finding.

The late-step detail, per arm:

  • The capture is role-DOMINANT, not role-exclusive: by late steps pirate's system arms also acquire smaller default-slot argmax rates — plain 0.104 at 60 steps rising to 0.256 at 120 (per-seed 0.18–0.32), padded 0.028 rising to 0.140 — against role's 0.868/0.864, replicating the epoch grid's system-arm default-slot rates of 0.10–0.25 at 2+ epochs.
  • Villain stays flat 0.000 in ALL arms at ALL points: not one of its 4,500 default-slot probes ever argmaxes the marker, and its per-seed log P stays parked between −9.7 and −13.2.

The template-overlap explanation from the epoch grid's default-slot finding — the bare assistant header is literally the system arms' own template skeleton, and the role label pirate_assistant shares most of it — comfortably absorbs both the system-arm capture and the role arm's stronger version; what it does not explain on its own is the persona-level asymmetry (villain flat everywhere), which remains the untested part at n = 2 personas.

Re-scored in logit space, the late-step gap on three of four cells doesn't shrink — it flips or shifts positive — but pirate's padded contrast stays clearly negative, so this is contrast-conditional, not a uniform role-vs-system property

The replication left one binding ambiguity: in trained log P space, villain's late-step gap drifts toward zero, but it does so exactly where the wrong-slot read re-enters the saturated floor. "The encodings converge" and "a persisting gap becomes unreadable down there" both predict the same drift-to-zero curve. The EOS-margin re-read was the cheap way to separate them — same 180 adapters, same 50 held-out questions, same probes, swap only the read-out from log P(marker) to Δ(z_marker − z_eos) trained − base. The marker and EOS share the same logZ, so the normalizer cancels and the read keeps headroom even where log P has none.

Two-panel line plot of the paired wrong-persona role-vs-system gap d = (system arm) minus (role arm), against optimizer steps on a log axis. Left panel trained on pirate, right on villain. Each panel shows four traces: two contrasts (plain and padded, solid vs dashed) in two DV spaces (trained log P in orange, trained minus base EOS-margin in blue) with 95% bootstrap confidence interval shading. Through 30 steps the orange and blue traces hug each other closely below zero on both panels. From 60 to 120 steps they fan apart: the orange log P lines drift toward zero from below on villain, while the blue EOS-margin lines climb past zero into clearly positive territory on villain plain and pirate plain at 120 steps. A grey shaded band at steps 5 to 18 is labelled implant not installed.

Figure. In log P space (orange) the gap drifts toward zero from below at late steps; in trained − base EOS-margin space (blue) the four cells split four ways at 120 steps — 2 of 4 are CI-clear positive (pirate plain and villain plain, villain plain knife-edge by 0.06 nat), 1 of 4 is mean-positive but CI-straddling (villain padded), and 1 of 4 stays CI-clear negative (pirate padded). Paired d = (system arm) − (role arm) at the wrong-persona teacher-forced probe; n = 5 seeds × 50 questions per point; bands = 95% bootstrap CIs over 5 seeds. Negative d = role has MORE wrong-persona marker mass; positive d = role has LESS. The plain contrast = system_plain − role; padded = system_padded − role. The two DVs are read off the SAME 540 per-cell scoring outputs.

What is striking. At 30 steps both DVs agree closely on the wrong-persona headline contrast (margin and log P track each other through the install peak on every wrong-persona cell, within 0.05-0.35 nat). They disagree at 30 steps on the OWN-persona rig-check probe — see the methods finding below. From 60 steps onward the two DVs also separate on the wrong-persona headline read. In log P space (orange, raw trained log P, replicating #547's body numbers within 0.01 nat), villain's gap shrinks to a knife edge at 120 steps (plain −0.12 with CI straddling, padded −0.46 with CI's upper edge 0.009 nat above zero), and pirate's plain contrast sits at +0.25 with CI's lower edge 0.011 nat below zero. In EOS-margin trained − base space (blue), the SAME data reads villain plain +0.79 (CI [+0.06, +1.52], CI clear of zero on the positive side, knife-edge by 0.06 nat) and villain padded +0.45 (CI [−0.05, +0.88], straddling but mean positive) at 120 steps; pirate plain reads +0.50 (CI [+0.21, +0.85], clear positive, all 5 seeds above zero); only pirate padded stays clearly negative (−0.52, CI [−0.71, −0.34], all 5 seeds below zero). What the figure CANNOT tell you: whether this is a property of role-vs-system at lr=5e-6 specifically or generalizes to other LRs / persona pairs, and the read still lives entirely below the argmax-marker emission threshold (the construct gap from the rest of the body carries unchanged).

Why the two DVs disagree. The per-encoding levels make this concrete. By 120 steps the wrong-persona Δmargin trained − base on villain has converged into a narrow band: role 6.88 nats, system_plain 7.68, system_padded 7.33 — all three encodings moved the marker logit upward by ~7 nats versus the base model, and on villain the role encoding moved it LEAST. The per-encoding picture on pirate at 120 steps is different: role 5.96, system_plain 6.46, system_padded 5.44 — role sits in the MIDDLE, with system_padded the lowest arm and system_plain the highest. The villain-plain headline cell is the cleanest version of the "role ends lowest" pattern; on pirate, the same pattern holds against system_plain (plain contrast positive) but reverses against system_padded (padded contrast clearly negative). The log P read at the same point sits at the floor (≈ −14 nats across all encodings) and compresses 1-nat differences in z_marker into noise.

Decomposing the headline +0.79 nat. The d_margin (paired, sys_plain − role at villain s=120 wrong-persona probe) splits into a Δz_marker contribution (sys_plain trained − base marker logit minus role trained − base marker logit, paired) of +0.48 nat (CI [+0.11, +0.81]) and a Δz_eos contribution of +0.32 nat (CI [−0.12, +0.74], straddling). Both terms push d_margin positive on the mean — system_plain ends up with a higher trained marker logit AND a lower trained EOS logit than role on villain at 120 steps — but only the marker-logit contribution has a CI clear of zero on its own; the EOS-logit contribution's CI straddles. So the mechanism is "both directions of role's EOS logit growing more relative to its marker logit and role's marker logit growing less than system_plain's", but on this n=5 the marker-logit term is the cleaner half of the decomposition. The full per-encoding trajectory across all six steps:

Two-panel line plot of per-encoding trained minus base EOS-margin shift against optimizer steps on a log axis. Both panels show three encodings (system plain in orange, system padded in green, role in blue) with bootstrap confidence interval shading. All three encodings ramp from near zero at 5 steps to a peak at 30 steps, where the role encoding peaks highest (11.4 nats pirate, 14.1 villain) above the system encodings, then decay back to a narrow band of 5 to 7 nats by 120 steps. On villain at 120 steps the role encoding is the lowest of the three (role 6.88, padded 7.33, plain 7.68). On pirate at 120 steps role sits in the middle (role 5.96, padded 5.44, plain 6.46) — system_padded is the lowest arm. A grey band at steps 5 to 18 is labelled implant not installed.

Figure. All three encodings ride a peak-and-decay shape in Δmargin space; the role encoding overshoots at install (s=30) on both personas, and by s=120 it sits the LOWEST on villain (which flips both villain contrasts positive on the mean) but the MIDDLE on pirate (lower than system_plain — which flips pirate plain positive — but higher than system_padded, which is what keeps pirate padded clearly negative). Per-encoding trained − base EOS-margin at the wrong-persona probe; bands = 95% bootstrap CIs over 5 seeds. The role-vs-plain crossover happens between 60 and 120 steps on both personas; system_padded stays below role at every step ≥ 30 on pirate, so pirate's padded contrast never crosses. This is the per-encoding decomposition the contrast d = (system − role) collapses into a single number.

Methods finding promoted from rig-validity. The spec's pre-stated check "at s=30 (off-saturation) the margin gap and the log P gap should agree closely, because Δlog Z ≈ 0" is empirically false on BOTH personas at the own-persona probe at s=30 — on villain by 1.2 nats and on pirate by 2.6 nats (the largest |margin − logP| disagreement anywhere in the grid). Pirate's Δz_eos between role and plain-system encodings differs by 2.3 nats at the install step, villain's by 1.0 nats. This is a real result, not just a rig-validity caveat: role-encoding training reshapes the post-response EOS-token distribution at install on every persona we tested, not just the marker — and on pirate the reshaping is larger and more EOS-driven than on villain. The headline DV Δ(z_marker − z_eos) is built to cancel logZ entirely, so the late-step interpretation does not depend on the falsified premise; but the falsified premise itself is a finding about how custom-role-header training redistributes mass at the response-boundary slot. Had the s=30 agreement check stayed a hard abort (it was demoted to a decomposed diagnostic mid-run, commit dcc69620a), the run would have failed on the own-persona disagreement and the late-step read below would not have been computed. Note: the s=30 wrong-persona headline contrast — the cell that feeds the read paragraph above — DOES see the two DVs agree closely (within 0.05-0.35 nat across the four wrong-persona cells), so the "DVs agree at install" claim holds where the headline reads it, even though the spec's broader premise about ALL s=30 probes does not.

What's settled, what isn't. The methods reread itself stands on solid ground at HIGH confidence within its scope: the recomputed log P from the four-float storage matches #547's stored vLLM log P across all 540 cells to within ~0.16 nat max MAE, four-float internal consistency holds to 1e-3, and the gauge assert confirms LoRA leaves the unembedding untouched so trained − base logit differences are gauge-free. The floor-compression-vs-encodings-converge ambiguity is partly resolved on three of four cells, where the late-step gap is no longer just shrinking — it is moving positive in trained − base EOS-margin space. But the resolution is uneven across the grid: pirate plain (clean positive, all 5 seeds positive) is the cleanest version, villain plain (mean +0.79, CI lower bound +0.06 nat — one seed of the two negative seeds away from straddling) is knife-edge, villain padded straddles, and pirate padded stays clearly negative. The interpretation that says "role's EOS logit moves more relative to its marker logit than the system arms'" is LOW-to-MODERATE confidence on the headline cell — it is consistent with the cleanly-positive cells, falsified on pirate padded (where role is NOT the lowest-margin arm by s=120), and the +0.06 nat headline CI lower bound is one bootstrap perturbation from straddling. What's not settled: whether any of this is a property of role-vs-system at lr=5e-6 or a particular trajectory of these 2 personas (the same n=2 caveat from the rest of the body), and whether the same reading translates to the on-policy emission DV the project rule names (the marker is the argmax in 0 of 9,000 wrong-slot probes in this re-read too — none of this lives in behavioral-emission space yet).

A representative cell. Per-seed paired d at villain s=120 (the cell whose CI cleanly — but knife-edge — clears zero on the positive side in EOS-margin space):

seedd_logP plain (raw, #547 DV)d_margin_T−B plain (this DV)d_logP padded (raw)d_margin_T−B padded
7+0.75+1.66−0.34+0.57
21+0.61+1.52−0.18+0.73
42−1.16−0.25−1.29−0.38
137−1.17−0.26−0.76+0.15
1337+0.37+1.29+0.26+1.17
mean (bootstrap point)−0.12+0.79−0.46+0.45
95% CI[−0.86, +0.61][+0.06, +1.52][−0.96, −0.03][−0.05, +0.88]
sign tally3 of 5 positive3 of 5 positive1 of 5 positive4 of 5 positive

The same five seeds; the same model, the same probes. The DVs disagree on the bootstrap mean for plain (raw log P stays slightly negative, margin T−B flips positive) while agreeing on sign for the padded contrast. Note: d_logP here is raw trained log P (g_logprob_sys − g_logprob_role, matching #547's body convention); d_margin is trained − base (Δmargin_sys − Δmargin_role). Both readings come from the SAME 540 per-cell forward passes — only the read-out and the base-subtraction differ. The bootstrap-mean row was sourced directly from analysis.json; the per-seed rows in the prior draft of this body were stale (they didn't average to this footer), and were regenerated from the per-cell JSONs by re-running the same (g_logprob_sys − g_logprob_role) / (Δmargin_sys − Δmargin_role) formula the figures script uses. The footer means and CIs were correct in the prior draft and are unchanged.

A second look at the raw per-seed values across every step makes the cross-step shape transparent — the cells in the table above sit on the right of the second panel:

Two-panel scatter of per-seed paired d in trained minus base EOS-margin space against optimizer steps from 5 to 120 on a log axis. Left panel trained on pirate, right on villain. Two contrasts per panel: plain contrast as blue circles and padded as orange triangles, 5 dots per step per contrast. Through 30 steps all points sit clearly below zero in both panels (clustering at minus 1 to minus 2.5 on villain at 30 steps). At 60 and 120 steps the points fan upward, crossing zero, with several per-seed values reaching plus 1 to plus 1.7 on villain plain at 120 steps and on pirate plain at 120 steps. A grey shaded band at steps 5 to 18 is labelled implant not installed.

Figure. Per-seed paired d in EOS-margin space — the same data the hero figure aggregates with a bootstrap. Every per-seed value is shown raw. The same install-window unanimity from the log P read is here too: at 30 steps every seed is below zero in every cell. The late-step fan-out is also here: at 120 steps villain plain has 3/5 seeds above zero (the knife-edge cell where the bootstrap CI lower bound is +0.06 nat — two of the five seeds, 42 and 137, are negative-mean at d ≈ −0.25), villain padded has 4/5 above zero with one seed at d ≈ −0.38, pirate plain has 5/5 above zero (the clean CI-positive cell), and pirate padded has 0/5 above zero. The bootstrap CIs in the hero figure are derived from these points; nothing is hidden in aggregation.

A scope caveat the previous findings carry but it's worth re-stating here: the EOS-margin DV is read off the same teacher-forced post-R slot under a base-model-greedy R, so it is the same off-distribution proxy that the parent's log P DV used, just less saturating. The construct of interest under the project's marker-leakage rule remains on-policy emission, which this rig does not measure (the marker is the argmax in 0/9,000 wrong-slot probes in this re-read, same as #547). What the margin re-read upgrades is the SHAPE of the late-step encoding-space story given the proxy; the proxy → construct gap is unchanged.

Spec note. The reread spec pre-specified two binary outcomes — "floor-compression wins" (the parent's late-step null was a measurement artifact: in margin space the gap stays negative throughout) and "encodings-converge wins" (the gap really does shrink toward zero: in margin space too, the late-step values straddle zero with mean-near-zero CIs). The data is neither: three of four cells move clearly above zero in margin space (one of those three knife-edge) and one stays clearly below — that's a third reading, not a refinement of either pre-stated binary. A faithful read of this finding against the spec is "off-spec, contrast-conditional", not "the encodings converge then invert across the board".

Under content-matched bare wording the install-window sign flips — bare role carries LESS wrong-persona marker mass than minimal system, on both personas, in both DV spaces, every per-seed value positive across all 3 install-onward grid points {30, 60, 120}, and the gap grows to +3.0 nats at s=60

The bare-wording grid is the cleanest discriminator the line has produced yet. If the parent's negative install-window gap had been a property of the role-header SLOT — <\|im_start\|>pirate_assistant\n vs <\|im_start\|>system\n...You are a pirate, master of the seas...<\|im_end\|>\n<\|im_start\|>assistant\n — stripping the elaborate instruction text out and stripping the _assistant suffix off the role label should have kept the sign negative. It does not. Under bare wording, the paired d = (minimal system) − (bare role) at the wrong-persona probe is clearly POSITIVE on both personas in both DV spaces from the install step onward, with every per-seed value positive at every grid point past s=18 and the bootstrap point estimate growing to +2.79 nats on villain at s=120.

Two side-by-side panels, one per trained persona, plotting paired d = (minimal system) − (bare role) at the wrong-persona probe against optimizer steps {18, 30, 60, 120} on a log axis. Each panel carries two traces with 95 percent bootstrap CI shading: trained − base log P in warm orange, trained − base EOS-margin in blue. At s=18 inside a shaded grey 'implant not installed' region the pirate-panel traces straddle zero (both near -0.15) and the villain log P trace straddles zero (-0.05) but the villain margin trace is CI-clear NEGATIVE (-0.23, CI lower bound -0.38). Both DVs then rise sharply through s=30 into clearly positive territory, peak around s=60 — at about +1.5 nats on the pirate panel and +3.0 nats on the villain panel — then plateau or slightly dip at s=120. From s=30 onward the two DV traces hug each other within about 0.3 nats.

Figure. Bare-word grid flips the sign and the two DVs agree throughout the install-onward range — bare role carries less wrong-persona marker mass than minimal system on both personas and in both DV spaces from s=30 onward. Paired gap d = Δlog P_minimal_system − Δlog P_bare_role (warm orange) and d_margin = Δ(z_marker − z_eos)_minimal_system − Δ(z_marker − z_eos)_bare_role (blue) at the wrong-persona teacher-forced probe, computed per seed and bootstrapped over 5 seeds (n = 50 questions × 5 seeds per point); shading = 95% percentile CI. Positive d means bare role carries LESS wrong-persona marker mass than minimal system (i.e. less leakage on the proxy DV). At s=18 (pre-install, gate fails both arms with own argmax-emit = 0.000) the read is mixed: log P straddles zero on both personas (pirate -0.14 CI [-0.48, +0.24]; villain -0.05 CI [-0.21, +0.09]); margin straddles zero on pirate (-0.19 CI [-0.52, +0.15]) but is CI-clear NEGATIVE on villain (-0.23 CI [-0.38, -0.08], 4/5 seeds negative) — a brief sub-install asymmetry that flips by the time the implant installs. At s=30 every per-seed value is positive on both personas in both DVs (pirate +0.56 log P / +0.61 margin; villain +0.81 / +0.55, 5/5 positive every cell); at s=60 the gap peaks (pirate +1.55 / +1.65; villain +3.02 / +3.14); at s=120 it plateaus (pirate +1.68 / +1.83; villain +2.79 / +2.86). Two DVs agree on the headline contrast throughout (max disagreement 0.27 nat on villain s=30) — the EOS-margin re-read this body's prior finding needed a separate adapter pass for happens inside one pipeline here.

What is striking. First, the sign reversal vs the elaborate-wording grid is large and unambiguous. Compare the same per-seed-paired bootstrap at s=30, both personas, in trained − base log P space:

Persona × wordingpaired d (Δlog P, sys − role) at s=30per-seed sign tally
Elaborate, plain − rolepirate −0.68, villain −1.825/5 negative each
Elaborate, padded − rolepirate −1.37, villain −2.495/5 negative each
Bare, minimal − bare rolepirate +0.56, villain +0.815/5 positive each

Same model, same data revision, same 50 questions, same lr, same step count, same seeds, same composition recipe — change only the announcement wording and the role label, and the sign flips. Second, the gap grows past install rather than decaying. In the elaborate-wording grid the negative gap was largest at install and drifted toward zero or knife-edge-positive in margin space by s=120; under bare wording the gap is smallest at install (+0.6 to +0.8 nat) and largest at s=60 (+1.5 to +3.0 nat), then either plateaus or slightly dips by s=120. Third, the two DVs track each other within 0.3 nat across the whole grid, with no late-step divergence — none of the floor-compression-vs-encodings-converge ambiguity the parent's elaborate-wording run produced shows up here, because the wrong-persona Δlog P levels stay in the readable band (peaking at +13.3 nats on villain s=30 then settling at +6 to +9 nats) rather than dropping into the saturated −15-nat floor.

The per-arm trained − base log P levels at the wrong-persona probe expose what is driving the contrast:

Two-panel figure showing trained-vs-base Δlog P at the wrong-persona probe per arm per persona across optimizer steps {18, 30, 60, 120}, with a lower strip showing own-encoding argmax-emit rate. Top row: minimal system in warm orange, bare role in blue, each with 95 percent bootstrap CI shading. Both arms ramp from about +6 nats at s=18 to a peak at s=30 — minimal system peaks at about +11.3 nats on pirate and +13.3 nats on villain, bare role peaks lower at about +10.8 and +12.5 nats — then both decay toward s=60 and s=120, with the bare role arm decaying further (down to about +6.5 and +6.6 nats by s=120, against +8.2 and +9.4 for minimal system). Bottom row: own-encoding argmax-emit rate climbs from 0 at s=18 to 0.7-1.0 at s=30 in both arms (bare role installs slightly faster), and 1.0 at s=60 and s=120.

Figure. Both arms push the wrong-persona marker UP at install (the install overshoot from the parent reproduces); minimal system overshoots more, then decays more slowly — so the post-install Δlog P gap is bare role under minimal system, growing. Top: trained − base log P at the wrong-persona probe per arm; lower = less leakage. Bottom: own-encoding argmax-emit rate vs the 0.5 install gate (dotted). Per-seed-bootstrap CI shading (n = 5 seeds × 50 questions per point per arm). Bare role installs slightly faster (pirate 0.99 vs 0.84 at s=30; villain 0.74 vs 0.64) but lifts the wrong-persona marker LESS at install AND decays more under continued training, which is what makes the (minimal system) − (bare role) contrast positive and growing. Grey shaded region = no installed implant.

Why this test. The bare-wording recipe pins everything that drove the parent's elaborate-wording finding — same base model, same LoRA recipe, same data revision, same lr, same seeds, same 50 held-out questions, same paired-bootstrap statistic, same install gate — and varies one thing: the announcement words. If the install-window negative gap is a property of the role-header SLOT (the <\|im_start\|>{persona}_assistant\n boundary vs the system-prompt boundary), bare wording preserves the slot identity and the negative gap should survive. If the gap is a property of the elaborate INSTRUCTION text or its interaction with the persona-flavoured role label, bare wording strips the content and the gap should disappear or reverse. The data says it reverses. Cleanly. Per-seed sign tally is unanimously positive in every install-onward cell of the bare-word grid, across both DV spaces. The teacher-forced proxy DV caveat still applies (the wrong-persona marker is the argmax in 0 of 4000 probes), so this is a less-leaky-on-the-proxy claim, not a behavioral-emission claim.

Sample raw per-cell numbers at the headline (villain s=30, wrong-persona probe — the cleanest install-window read; cherry-picked for illustration; full 240 cross-eval per-cell JSONs at eval_results/issue_533/bare_word_install_step_grid/cross_eval/per_cell/):

TRAINING SETUP — bare-word minimal_content_cn recipe, lr=5e-6, max_steps=30
  arm = system_minimal  (system prompt = "You are a pirate.", 2 pad-parity ` pad` tokens appended to the user message for length parity)
  arm = role_bare       (system prompt = "You are a helpful assistant.", bare `pirate` role header)
  marker = ` ※` (Qwen-2.5 BPE id 83399), marker-only loss, MarkerOnlyDataCollator tail_tokens=0
  composition = 300 positives (this persona) + 150 marker-less other-persona + 150 marker-less default-assistant

EVAL PROBE — teacher-forced log P at the post-R slot, R = base-model greedy
  trained: villain, eval encoding: <other persona = pirate>

PER-SEED Δlog P (trained − base) on the WRONG-persona (pirate) probe:
  (values regenerated verbatim from the per-cell JSONs; seed order [7, 21, 42, 137, 1337])
                        sys_minimal      role_bare       d = sys − role
  seed=7:                 +13.037         +12.349          +0.688
  seed=21:                +13.292         +12.150          +1.141
  seed=42:                +13.367         +12.992          +0.375
  seed=137:               +13.166         +12.470          +0.696
  seed=1337:              +13.813         +12.688          +1.125
  ──────────────────────────────────────────────────────────────
  per-seed-paired bootstrap point (N=10,000): d̄ = +0.805 nat
  95% CI:                                     [+0.564, +1.046]
  sign tally:                                 5 of 5 seeds positive

EVAL ARTIFACT — none (this is teacher-forced proxy DV; no model generation;
  each per-cell JSON stores `(g_logps_per_q, b_logps_per_q, g_argmax_marker_per_q, ...)`)

OWN-ENCODING ARGMAX-EMIT (install diagnostic): sys_minimal = 0.640, role_bare = 0.740 (both PASS the 0.5 gate)
WRONG-PERSONA ARGMAX-MARKER (behavioral): 0/250 probes (0/50 × 5 seeds) for BOTH arms — same construct gap as parent.
Per-seed paired d at the other 7 grid points (5 install-onward + 2 pre-install at s=18; cherry-picked for illustration; full per-cell JSON data linked inside)
(persona, step)per-seed d (sys_minimal − role_bare), Δlog P, seeds {7, 21, 42, 137, 1337}bootstrap point95% CI
pirate s=18 (pre-install)−0.70, +0.43, −0.34, −0.34, +0.25−0.14[−0.48, +0.24]
pirate s=30+0.27, +0.86, +0.47, +0.59, +0.60+0.56[+0.39, +0.73]
pirate s=60+1.13, +1.77, +2.09, +1.68, +1.05+1.55[+1.21, +1.88]
pirate s=120+1.71, +2.02, +1.64, +2.04, +0.99+1.68[+1.33, +1.97]
villain s=18 (pre-install)+0.16, −0.20, +0.06, −0.30, +0.02−0.05[−0.21, +0.09]
villain s=60+3.64, +3.17, +1.94, +2.68, +3.65+3.02[+2.43, +3.55]
villain s=120+3.21, +2.38, +2.51, +2.69, +3.13+2.79[+2.50, +3.08]

Full 240 cross-eval per-cell JSONs at eval_results/issue_533/bare_word_install_step_grid/cross_eval/per_cell/ + 245 logit-capture per-cell JSONs at eval_results/issue_533/bare_word_install_step_grid/logit_capture/per_cell/. Margin-space (trained − base EOS-margin) numbers track these within 0.3 nat across all 8 grid points (max disagreement villain s=30 = 0.27 nat).

What this rules out, what it doesn't. The elaborate-wording grid's negative install-window gap is now best read as a property of the wording or label, not of the role-header structural slot per se. Two readings remain on the table for which sub-component of "wording" drives it: (a) the elaborate INSTRUCTION text in the system prompt (the "You are a pirate, master of the seas..."), or (b) the elaborate _assistant suffix on the role label (pirate_assistant\n vs bare pirate\n). The bare-word grid changed both simultaneously, so it cannot separate them. A clean third arm — bare-text system prompt with the elaborate _assistant-suffix role header, or its dual — would pull them apart; that is the natural next-experiment knob.

Scope of the "less leaky" claim. The sign flip lives entirely at the wrong-persona probe (the headline DV under the frontmatter Goal). On the default-assistant probe the direction is the OPPOSITE: under bare wording BOTH arms on pirate capture the default slot at argmax rates 0.84 (sys_minimal) and 0.94 (role_bare) by s=120, against the elaborate run's 0.10-0.25 (system_plain/padded) and 0.86 (role) — so bare wording bought wrong-persona separation at the cost of much heavier sys-AND-role leakage to the default context. The open question on leakage-to-default (q:leak-to-default 3.7) sits at the default-slot probe, not the wrong-persona probe; "less leaky" in this finding's headline does NOT extend there.

Alternative readings considered.

  • Install-overshoot asymmetry, not encoding selectivity. The per-arm levels in the second figure above show both arms peaking at s=30 (the install overshoot from the parent reproduces) and minimal-system overshooting MORE than bare-role (peak Δlog P 13.34 vs 12.53 nats on villain, 11.33 vs 10.77 on pirate) before both decay. A simpler reading of the positive d at s=30 would be "bare role just installs the wrong-persona marker mass less aggressively at the overshoot peak, and the contrast reflects nothing more than that one-step asymmetry." But this reading does NOT carry to s=60 or s=120, where the gap GROWS while both arms have already turned the corner past the peak and are decaying — so a pure overshoot-asymmetry reading would predict the gap to shrink past install, not grow to +3.0 nats. The growing gap is the part that says the encoding-arm asymmetry persists past the overshoot peak, not just at it.
  • #464's bare-word endpoint result was directionally consistent. The #464 bare-word follow-up's endpoint read at full convergence (lr=1e-5, 5 epochs, 3 seeds; CI-positive role-better at the wrong-persona probe — the result this run's spec called out as already-known for the endpoint) sits in the same direction as this run's lr=5e-6 install-step trajectory. Different LR, different training amount, different seed pool, same direction — modest cross-rig support for "bare role carries less wrong-persona marker mass than minimal system" being a stable feature of bare-wording training rather than an artifact of either grid alone.
  • Contrastive-negatives composition collapsing under bare wording. The bare wording's negative rows are also bare; both positives AND negatives changed at once. A clean test would hold positive wording fixed and vary only the negative-row wording, or vice versa. Currently the bare-word grid cannot rule this in or out.
  • lr=5e-6 / 2-persona / this-data-revision cell-specific. The per-seed unanimity (5/5 positive at every install-onward cell × DV space — 60 of 60 (seed × step × persona × DV) (seed, step ∈ {30, 60, 120}, persona, DV) cells in the predicted direction) and the size of the effect (point estimates growing to +3.0 nats with CI widths < 1 nat) make a noise-driven explanation unlikely, but the same n=2 caveat that limits the parent's confidence carries here. More personas + lr=2e-6 is the named next-step.

What's NOT settled. (i) The teacher-forced proxy DV. The on-policy emission DV the marker-leakage rule names is still not measured — under free decoding the trained model writes its own R and the post-R slot is no longer fixed. Both the elaborate negative gap and this bare positive gap live entirely below argmax-marker emission (0 of 4000 wrong-persona probes here, same as parent). (ii) Only 2 personas, 1 LR. The parent's n=2 caveat carries; the bare-wording grid hasn't seen lr=2e-6 or a third persona. (iii) The default-slot capture is much more aggressive under bare wording — see the scope-of-claim paragraph above; the wrong-persona-probe headline does NOT imply less leakage on the default-context probe, where the leak-to-default open question (q:leak-to-default 3.7) actually lives.

Confidence on this finding alone is MODERATE. The sign flip is unanimous across 5 seeds in every install-onward cell of the bare-word grid in BOTH DV spaces (60 of 60 (seed × step × persona × DV) cells in the predicted direction at s ∈ {30, 60, 120}), the bootstrap CIs are tight (worst-case lower-bound 0.20 nats from zero on pirate s=120 log P), the two DVs agree closely throughout, and the comparison against the elaborate-wording grid is single-variable (only the announcement wording changes). What caps it short of HIGH: the same n=2 persona caveat, the same teacher-forced proxy caveat, the simultaneous-change confound between instruction text and role-label suffix, the brief sub-install villain-margin negativity at s=18, and the much heavier default-slot leakage that bare wording brings on the side.

Next steps

  • Disentangle which sub-component of "wording" carries the sign — add a third arm that varies ONE of (instruction text, role-label suffix) at a time. Concretely: one arm with the elaborate "You are a pirate, master of the seas..." system prompt but a bare pirate role header, and one arm with the minimal "You are a pirate." system prompt but a pirate_assistant role-suffix header. Same recipe, same install-step grid. Currently the bare-vs-elaborate change varies both at once (cost_class: needs-gpu, headline_affecting: yes).
  • Replicate the bare-word sign flip at one more LR (lr=2e-6 — the recipe rule's named other safe point) and on a third persona to test whether the +0.6 to +3.0 nat positive d range is a property of the encoding regime or of (pirate, villain) at lr=5e-6 (cost_class: needs-gpu, headline_affecting: yes).
  • Re-map the bare-word grid into the install cliff — points at {20, 22, 24, 26, 28, 34} steps — to time where the leakage-grade gap first becomes readable under bare wording (cost_class: needs-gpu, headline_affecting: no).
  • Rank reduction (r=16 / r=8) at the s=30 anchor under bare wording, where both arms install fast and the gap is clearly positive (cost_class: needs-gpu, headline_affecting: no).
  • Question-level paired bootstrap at s=30 (resampling the 50 questions within seeds, in both grids) to tighten the install-window CIs (cost_class: free-analysis, headline_affecting: no).
  • Re-read the elaborate-wording margin-space late-step sign flip at one more LR / one more persona pair to test whether the early-vs-late sign flip is a property of elaborate-wording role-vs-system or of these specific 2 personas at this LR (cost_class: needs-gpu, headline_affecting: yes).

Reproducibility

Parameters:

ParameterValue
Base modelQwen/Qwen2.5-7B-Instruct
AdapterLoRA, r=32, α=64, dropout=0.05, target attention projections
OptimizerAdamW, lr=5e-6 (the one manipulated variable vs the parent run), cosine schedule (warmup 0.05), bf16
Marker (leading space), Qwen-2.5 BPE token id 83399 (asserted at launch)
Lossmarker-only via MarkerOnlyDataCollator, marker_tail_tokens=0, marker_band_stop=False
Training rows per cell600 (300 positive + 150 other-persona negative + 150 bare-assistant negative)
Source personaspirate, villain (trained separately, single-persona LoRA per cell)
Encoding armssystem_plain, system_padded (length-matched), role (custom chat-role header)
Epoch settings1, 2, 3, 5
Seeds42, 137, 1337, 7, 21
Batch / grad accum / max length4 / 4 / 2048
Cells trained120 (3 arms × 2 personas × 5 seeds × 4 epoch settings)
EvalvLLM teacher-forced prompt_logprobs=1 at the post-R slot (R = base-model greedy), 50 held-out questions, 3 eval encodings per cell (own / wrong / bare-assistant) = 360 per-cell JSONs
Statsper-seed-paired bootstrap N=10,000 over 5 seeds, 95% percentile CI; per-seed d = log P_arm − log P_role with per-persona × per-contrast splits computed at every epoch since no anchor was resolved; recomputation done in the figures script directly from per-cell JSONs, not in analysis.json
Hardware4× H100 (RunPod ephemeral); pod-533
Hydra confign/a (not Hydra; dispatcher is scripts/i533_cn_run.sh)

Artifacts:

Compute:

  • ~18 GPU-hours on 4× H100 (matches the parent's measured budget; the LR change does not affect wall time per cell).
  • Wall time: ~6 hours including upload and cross-eval.
  • Pod: pod-533 (provisioned ephemeral, terminated 2026-06-10 after upload-verification PASS).

Code:

  • Repo commit (issue worktree branch, figures + script): 259a4413cf23c13b8122a6be3758681f40d24655 on the issue-533 branch.
  • Training entrypoint: scripts/i464_phase23_train.py (cherry-picked onto issue-533 from the issue-529 branch, no src/ changes)
  • Dispatcher: scripts/i533_cn_run.sh (forked from i529_cn_run.sh with --lr 5e-6)
  • Eval entrypoint: scripts/i464_po_eval.py (variant cn_i533 registered)
  • Anchor selection: scripts/i529_select_anchor.py (parametrized with --in-dir to point at eval_results/issue_533/...)
  • Analysis (skipped headline on degenerate anchor): scripts/i464_po_analyze.py (variant cn_i533 registered; the per-persona × per-contrast paired-bootstrap block is gated on resolved anchor, so it wrote a partial_anchor_skipped stub and did NOT compute the per-persona numbers — those came from the figures script below)
  • Plot script (also computes the per-persona × per-contrast paired bootstrap directly from per-cell JSONs): scripts/i533_clean_result_figures.py
  • Launch command (the canonical nohup): nohup bash scripts/i533_cn_run.sh > /workspace/logs/issue-533-cn-run.log 2>&1 & echo $! > /workspace/logs/issue-533-cn-run.pid

Install-step replication (merged from #547, 2026-06-10)

Parameters:

ParameterValue
Base modelQwen/Qwen2.5-7B-Instruct
AdapterLoRA, r=32, α=64, dropout=0.05, target attention projections
OptimizerAdamW, lr=5e-6, cosine schedule (warmup_ratio 0.05, computed off each run's own max_steps), bf16
Marker (leading space), Qwen-2.5 BPE token id 83399 (asserted at launch)
Lossmarker-only via MarkerOnlyDataCollator, marker_tail_tokens=0, marker_band_stop=False (deliberate: the max_steps grid IS the training-amount dial)
Training rows per cell600 (300 positive + 150 other-persona negative + 150 bare-assistant negative)
Training-amount grid (the manipulated variable)max_steps ∈ {5, 10, 18, 30, 60, 120} ≈ epochs {0.13, 0.27, 0.48, 0.80, 1.60, 3.20} at 37.5 steps/epoch; each grid point a separate complete run with its own cosine schedule
Source personaspirate, villain (single-persona LoRA per cell)
Encoding armssystem_plain, system_padded (length-matched), role (custom chat-role header)
Seeds42, 137, 1337, 7, 21
Batch / grad accum / max length4 / 4 / 2048
Cells trained180 (3 arms × 2 personas × 5 seeds × 6 max_steps settings)
EvalvLLM teacher-forced prompt_logprobs=1 at the post-R slot (R = base-model greedy), 50 held-out questions, 3 eval encodings per cell (own / wrong / bare-assistant) = 540 per-cell JSONs
Statsper-seed-paired bootstrap N=10,000 over 5 seeds, 95% percentile CI; PRIMARY = unconditional trajectory_per_persona block in analysis.json (implant-active gate: both contrast arms own argmax-emit ≥ 0.5); anchor-gated headline skipped (partial anchor: villain s=30, pirate unresolved); pre-install ungated read = descriptive per-seed means from the per-cell JSONs, no bootstrap (exploratory)
Hydra confign/a (not Hydra; dispatcher is scripts/i547_cn_run.sh)

Artifacts:

  • Training data (REUSED, pin enforced in code via the DATA_REVISION constant): superkaiba1/explore-persona-space-data R_canon tree

  • Trained LoRA adapters — checkpoint deviation: 148/180 dirs on the HF model repo at adapters/i547_* (Hub-listed at write time: 148 complete dirs incl. safetensors at revision 3683ee29b8a415c325d1d83687641141c6c91819); the remaining 32/180 (all role-arm) live on the WandB Artifact thomasjiralerspong/explore-persona-space/i547-missing-adapters:v0 (COMMITTED, 10.84 GB, 352 files = 32 dirs × 11 files, manifest-verified) because the HF account hit its public-storage quota (persistent 403) mid-run. Remediation once quota is freed: scripts/i547_reupload_missing_adapters.py.

  • Per-cell teacher-forced log-prob JSONs (540 = 180 cells × 3 eval encodings — the raw eval output; no sampled completions exist under this teacher-forced rig): eval_results/issue_547/contrastive_negatives/cross_eval/per_cell/

  • Primary analysis (unconditional trajectory_per_persona; headline_status: partial_anchor_skipped): eval_results/issue_547/contrastive_negatives/analysis.json

  • Anchor-selection diagnostic (villain s=30 resolved, pirate unresolved): eval_results/issue_547/anchor_selection.json

  • Figures (PNG + PDF + commit-pinned meta sidecars): final relabeled set (all six, reader-facing in-figure text) at figures/issue_547/ @ 7e187b8f; source scripts scripts/i547_clean_result_figures.py and scripts/i547_preinstall_ungated_figure.py. Figure-data provenance: the trajectory and per-seed-scatter figures read the trajectory_per_persona block of analysis.json directly (never a private recomputation); the level figures read the per-cell JSONs.

  • Training metrics: 181 finished WandB runs named i547_* (180 unique cells + 1 smoke duplicate) in project thomasjiralerspong/huggingface

  • Reused training corpus from #464 (via #529 and the epoch-grid stage of this task): superkaiba1/explore-persona-space-data/issue464_role_vs_system/R_canon @ dc0b171f117d3b325695954a4de25deac3468502 — fit: same base model + same marker-only contrastive-negative recipe; data reuse IS the single-variable contract (only the training-amount indexing changed), and the pinned revision was Hub-verified to carry all 5 files the pipeline loads.

  • Reused eval results from the epoch-grid stage of this task (read-only ghost overlays in the figures): repo-relative eval_results/issue_533/contrastive_negatives/cross_eval/per_cell/ (360 JSONs) — fit: identical eval rig and DV (teacher-forced post-R marker log P, same 50 questions, same encodings), which is what makes the step-equivalent overlay and the 120-step-vs-3-epoch rig check valid.

  • Reused pipeline scripts from the epoch-grid stage's issue-533 branch (13-file cherry-pick: train/eval/analyze/anchor scripts + 2 experiment modules) — fit: same training and eval code path is the comparability contract; the only new code is the max_steps plumbing, the cn_i547 variant registration, the anchor-grid generalization, and the data-revision pin.

  • Methodology reference: docs/methodology/issue_547.md · gist

Compute:

  • 4× H100 (RunPod ephemeral pod-547, intent ft-7b), terminated after upload-verification PASS.
  • Training: 180 cells, 4-way sharded, ≈ 2 h wall (07:55–09:52 UTC, 2026-06-10) ≈ 8 GPU-h. Cross-eval + anchor + analysis: ≈ 40 min single-GPU including one eval relaunch. Total ≈ 12 GPU-h (plan budget 20).
  • Eval relaunch note: the first cross-eval attempt aborted when the HF pre-download 404'd on the 32 quota-blocked adapters; phases 4-7 were relaunched with EPM_LOCAL_ADAPTER_OVERRIDE reading the pod-local copies of the same adapter files — science identical, wall +17 min.

Code:

  • Branch issue-547, tip 1b60f12b66802de73468c0ad5c4967f00dfeae7c (eval-results commit fc6edc9b581903cda6d63627b5f3bae1436e97ed). Key commits: 8ffac18e1 (DATA_REVISION pin threaded through every data-repo fetch), a77ea2993 (cn_i547 registration + unconditional trajectory_per_persona block), 97d3d7bc4 (anchor selector generalized to an integer grid), 2ba716d87 (i547_cn_run.sh dispatcher + figures fork), acdda42be (resume launcher), c18bcb4f7 (eval results), 1b60f12b6 (figure relabel: reader-facing in-figure text).
  • Training entrypoint: scripts/i464_phase23_train.py (--issue 547 --max-steps {s} --lr 5e-6 --shared-marker --contrastive-negatives --no-traj)
  • Dispatcher: scripts/i547_cn_run.sh; eval scripts/i464_po_eval.py (variant cn_i547); analysis scripts/i464_po_analyze.py; anchor scripts/i529_select_anchor.py (--grid 5,10,18,30,60,120 --suffix-char s)
  • Reproduce: nohup bash scripts/i547_cn_run.sh > /workspace/logs/issue-547-cn-run.log 2>&1 & then uv run python scripts/i464_po_analyze.py --variant cn_i547 --anchor-file eval_results/issue_547/anchor_selection.json, uv run python scripts/i547_clean_result_figures.py, and uv run python scripts/i547_preinstall_ungated_figure.py.

Logit-margin re-read (inline follow-up, 2026-06-10)

Parameters:

ParameterValue
Read-out spaceEOS-margin Δ(z_marker − z_eos) = (z_marker − z_eos)_trained − (z_marker − z_eos)_base; secondary readouts Δlog P(marker) and Δz_marker from the same forward pass
Adapters re-scored180 (the same 3 arms × 2 personas × 5 seeds × 6 max_steps cells trained in the install-step replication above); no training
Adapter fetchDual-path: 148 dirs from HF model repo superkaiba1/explore-persona-space/adapters/i547_*, 32 role-arm dirs from WandB Artifact thomasjiralerspong/explore-persona-space/i547-missing-adapters:v0 (10.84 GB, 32 dirs × 11 files, manifest-verified). The artifact path covers the quota-blocked subset documented in the install-step replication block above
Eval probes50 held-out questions per cell × 3 eval encodings (own / wrong / bare-assistant) = 540 per-cell JSONs, identical pinned R_canon_test.json (data-repo dc0b171f117d3b325695954a4de25deac3468502)
Marker / EOSmarker (Qwen-2.5 BPE id 83399) asserted at launch; EOS <|im_end|> (id 151645)
EngineHF Transformers teacher-forced forward pass, batched, bf16; per-question capture of (log P(marker), z_marker, z_eos, logZ) per side
Headline contrastd_margin = Δ(z_marker − z_eos)_arm − Δ(z_marker − z_eos)_role at the wrong-persona probe, per (persona, contrast ∈ {plain−role, padded−role}, step); per-seed-paired bootstrap N=10,000 over 5 seeds, 95% percentile CI; computed in scripts/i533_margin_figures.py directly from the 540 per-cell JSONs
Secondary contrast (in analysis.json)role − system_plain at the OWN-persona probe — a narrower question; retained as a cross-check, not the headline
Rig validity gatesFirst, per-cell z_marker − logZ vs #547's stored vLLM log P(marker): trained MAE mean 0.063 nats, max 0.16; base MAE mean 0.074, max 0.089. Second, four-float internal consistency log P == z_marker − logZ < 1e-3 per cell per side. Third, the spec's s=30 "margin gap ≈ log P gap" premise demoted to a decomposed diagnostic mid-run (commit dcc69620a) — empirically false on villain at s=30 because role training reshapes the EOS distribution, not rig breakage; the margin DV cancels logZ so it does not depend on the falsified premise
Statistical-test rationalePer-seed-paired bootstrap pairs the same seed's role and system arms (shared init and data order), removing cross-seed variance from the contrast — the same recipe the parent run uses; CIs are 95% percentile over 10,000 resamples of the 5 per-seed d's. CIs that just barely clear / straddle zero are read with the same knife-edge caution the rest of the body applies to its bracketing-point comparisons

Artifacts:

  • Margin scoring output (540 per-cell JSONs + analysis.json + adapter_manifest.json): eval_results/issue_533/logit-margin-reread/ on branch issue-533-margin
  • Figures (PNG + PDF + commit-pinned meta sidecars): figures/issue_533/margin_*margin_paired_gap_trajectory, margin_paired_gap_per_seed_scatter, margin_per_arm_trajectory
  • Reused trained adapters from the install-step replication above (#547, via this task's merged section): the same 148 HF dirs at superkaiba1/explore-persona-space/tree/3683ee29.../adapters/i547_* plus the 32-dir WandB Artifact thomasjiralerspong/explore-persona-space/i547-missing-adapters:v0. Fit: same Qwen-2.5-7B-Instruct + LoRA r=32 / attention-projections-only / marker-only-loss / lr=5e-6 / 30-60-120 step training; reuse is the single-variable contract for this follow-up (only the read-out space changes). Adapter resolution verified against the HF Hub revision and the WandB artifact manifest at scoring time
  • Reused eval inputs from the install-step replication: same 50 held-out R_canon_test.json questions, same three eval encodings per cell, same pinned data-repo revision dc0b171f117d3b325695954a4de25deac3468502. Fit: same probe surface means the margin and log-prob reads measure the same teacher-forced post-R slot from the same model under the same context
  • The teacher-forced rig produces no model completions, so there are no raw-completion samples to link; the 540 four-float per-cell JSONs ARE the raw output

Compute:

  • 1× H100 (RunPod ephemeral, intent eval), terminated after upload-verification PASS.
  • Wall time: ≈ 1.9 GPU-h for ≈ 350 base greedy R generations + ≈ 27K trained-side and ≈ 1K base-side batched forwards + 180 adapter hot-swaps + 10.84 GB WandB-Artifact download; matches the spec's ~4 GPU-h envelope under budget.

Code:

  • Branch issue-533-margin, eval-payload commit ad23fb743ee80941cd56fbfba065bb88d0838080. Key commits: 4d534b95f (initial scorer + phase pipeline), cf431641e (reconciler-mandated hardening — gauge assert on cached adapters; production completeness gates in phase_analysis), 2279caf4e (Spearman validation gate advisory at tiny MAE), dcc69620a (demote s=30 margin-vs-logp abort to decomposed diagnostic; four-float internal-consistency hard gate), ad23fb743 (eval payload).
  • Scoring entrypoint: scripts/i533_margin_run.py (phases: env-check, R-generation, score, analyze; production gates: gauge assert, full-seed pair, four-float internal-consistency)
  • Figures: scripts/i533_margin_figures.py on main — computes the wrong-persona paired bootstrap directly from per-cell JSONs and writes all three figures
  • Reproduce: nohup uv run python scripts/i533_margin_run.py > /workspace/logs/issue-533-margin-run.log 2>&1 & then uv run python scripts/i533_margin_figures.py

Bare-word install-step grid (inline follow-up, 2026-06-11)

Parameters:

ParameterValue
Base modelQwen/Qwen2.5-7B-Instruct
AdapterLoRA, r=32, α=64, dropout=0.05, target attention projections
OptimizerAdamW, lr=5e-6, cosine schedule (warmup_ratio 0.05, computed off each run's own max_steps), bf16
Marker (leading space), Qwen-2.5 BPE token id 83399 (asserted at launch); shared-marker across personas
Lossmarker-only via MarkerOnlyDataCollator, marker_tail_tokens=0, marker_band_stop=False
Training rows per cell600 (300 positive + 150 other-persona marker-less negative + 150 bare-assistant marker-less negative)
Training-amount grid (the manipulated variable)max_steps ∈ {18, 30, 60, 120} ≈ epochs {0.48, 0.80, 1.60, 3.20} at 37.5 steps/epoch; each grid point a separate complete run with its own cosine schedule (parent's design-consistency rule)
Source personaspirate, villain (single-persona LoRA per cell)
Encoding arms (the SECOND manipulated variable, vs the parent install-step grid)system_minimal ("You are a pirate."/"You are a villain." system prompt + 2/3 pad-parity pad tokens appended to the user message for length parity) and role_bare (neutral "You are a helpful assistant." system prompt + bare pirate/villain role-header label, NO _assistant suffix); both verbatim from the #464 minimal_content_cn recipe's encoding pair
Seeds42, 137, 1337, 7, 21
Batch / grad accum / max length4 / 4 / 2048
Cells trained80 (2 arms × 2 personas × 5 seeds × 4 max_steps)
EvalvLLM teacher-forced prompt_logprobs=1 at the post-R slot (R = base-model greedy) for 240 per-cell JSONs (80 cells × 3 eval encodings: own / wrong-persona / bare-assistant), PLUS HF four-float logit capture (log P, z_marker, z_eos, log Z) per question for trained + base sides on the same 50 questions × 80 cells × 3 encodings = 245 per-cell JSONs (5 shared base-side files). Both passes inside one pipeline so the EOS-margin DV is available without a separate adapter re-read
Statsper-seed-paired bootstrap N=10,000 over 5 seeds, 95% percentile CI; PRIMARY = paired d = Δlog P(sys_minimal) − Δlog P(role_bare) at the wrong-persona probe in BOTH trained − base log P AND trained − base EOS-margin space; install gate = own-encoding argmax-emit ≥ 0.5 in BOTH arms (pass at s ∈ {30, 60, 120}, fail at s=18); statistical-test rationale identical to the parent's paired bootstrap
Hydra confign/a (not Hydra; dispatcher is scripts/i533_bw_run.sh)

Artifacts:

Compute:

  • 8× H100 (RunPod ephemeral, intent ft-7b), terminated after upload-verification PASS.
  • Training: 80 cells, 8-way sharded, total ~10 GPU-h including one 429 relaunch (the resume picked up from the partial WandB project state without re-training completed cells).
  • Cross-eval + logit-capture + analysis: ≈ 1 h single-GPU, batched HF forwards.

Code:

  • Branch issue-533-bareword, tip ac67bd7cf603c72d89bf01db0df3058ce6742212. Key commits: 294ad2c71 (port train+eval+capture+analyze rig for bw_i533 variant), 21e78f93d (align capture label with cross-eval/analyzer + non-empty analyzer smoke), 4b8b17b57 (retry-with-backoff on HF 429 in _missing_on_hub), a46f023f2 (replace _missing_on_hub list_repo_files with per-file file_exists), 3c998200f (eval payload), ac67bd7cf (figures + figures script).
  • Training entrypoint: scripts/i464_phase23_train.py (--issue 5331 --single-persona --shared-marker --contrastive-negatives --max-steps {s} --lr 5e-6 --no-traj)
  • Dispatcher: scripts/i533_bw_run.sh (forked from i547_cn_run.sh with arms swapped to {system_minimal, role_bare} and the max_steps grid trimmed)
  • Eval entrypoint: scripts/i464_po_eval.py (variant bw_i533 registered)
  • Analyzer: scripts/i533_bw_analyze.py
  • Figures: scripts/i533_bw_figures.py
  • Reproduce: nohup bash scripts/i533_bw_run.sh > /workspace/logs/issue-533-bw-run.log 2>&1 & then uv run python scripts/i533_bw_analyze.py && uv run python scripts/i533_bw_figures.py

Questions linked from the research hub

curated, not exhaustive