Context
The report card measures a vector's on-target effect and its coherence, but not whether steering one concept quietly drags a generation toward an unrelated concept (off-target drift). Since steerbench already ships several effect scorers, the same generated texts can be scored with every scorer to expose cross-concept leakage — using vectors and generations that are provided, never re-extracting anything.
Proposal
Given the steered generations already produced by the sweep (the text the dose CSV was scored from, provided as an input column or an adjacent file), score each generation with every registered effect scorer and report an off-target drift matrix: for the vector's own concept vs each other concept, the mean shift off baseline. This consumes existing scorers and existing generations only.
Acceptance criteria
- Add a pure function that takes per-seed baseline and steered generations plus a concept name and returns, per registered scorer, a
MetricStat shift off baseline (reuse _combine for the mean +/- std aggregation across seeds).
- The vector's own concept is the diagonal; other concepts are the off-target entries. No extraction, no model calls in the core function — text in, numbers out.
- Stochastic metric rule: require >= 3 seeds, report mean +/- std per cell, and document that seeds/hardware/wall-clock are recorded in the run provenance.
- Render the matrix as a small table in the report (markdown + HTML).
- CPU-only unit tests using canned generations: a formality-steered set that also reads as more positive shows a non-zero sentiment off-target entry; a neutral set shows near-zero off-diagonal. No model download.
ruff check ., ruff format --check ., mypy src, pytest -q all pass.
Context
The report card measures a vector's on-target effect and its coherence, but not whether steering one concept quietly drags a generation toward an unrelated concept (off-target drift). Since steerbench already ships several effect scorers, the same generated texts can be scored with every scorer to expose cross-concept leakage — using vectors and generations that are provided, never re-extracting anything.
Proposal
Given the steered generations already produced by the sweep (the text the dose CSV was scored from, provided as an input column or an adjacent file), score each generation with every registered effect scorer and report an off-target drift matrix: for the vector's own concept vs each other concept, the mean shift off baseline. This consumes existing scorers and existing generations only.
Acceptance criteria
MetricStatshift off baseline (reuse_combinefor the mean +/- std aggregation across seeds).ruff check .,ruff format --check .,mypy src,pytest -qall pass.