-
Notifications
You must be signed in to change notification settings - Fork 0
Home
- Technical Description
-
Mathematical Pipeline
- Overview
- Stage 0: Weight Delta Computation
- Stage 1: Forward Pass and Activation Capture
- Stage 2: ASM — Alignment Stress Map
- Stage 3: LTP — Lateral Tension Profile
- Stage 4: SFD — Spectral Field Density
- Stage 5: Behavioral Comparison
- Stage 6: Rank Displacement
- Stage 7: Candidate Graph Topology
- Stage 8: Batch Statistical Aggregation
- Notation Summary
- Visualization Pipeline
- Token Variance Analysis
- Engine Configuration
TASM (The Alignment Stress Map) is a web-based analysis platform for measuring alignment signals in transformer language models at inference time. It implements four complementary instruments — ASM (amplitude), LTP-RD (directional/rank displacement), SFD (dimensionality), and Token Variance (cross-context stability) — that together characterize the corrections introduced by instruction-tuning (RLHF/SFT) relative to a base model. The theoretical framework is described in two companion papers by Ostrander (2026).
The application is a single-server Python system built on FastAPI, serving a single-page web frontend over HTTP. It is designed for interactive single-prompt analysis, CSV-driven batch experiments, conversational probing via a built-in chat interface, and extensible post-hoc analysis via the module framework. All measurement-affecting parameters are centrally configured and surfaced in the UI.
TASM is structured as a monolithic FastAPI application (app.py, ~1,970 lines) backed by a modular engine layer:
| Module | Responsibility |
|---|---|
model_manager.py |
Model loading, weight delta computation, forward-hook installation, activation caching |
analyzer.py |
Orchestrates the full analysis pipeline: ASM, LTP, SFD, and behavioral comparison in a single forward pass |
ltp.py |
Lateral Tension Profile computation: counterfactual probing, PCA trajectories, M/C/V/L statistics |
sfd.py |
Spectral Field Density: QK-subspace engagement measurement via SVD projection; rank displacement computation |
engine_config.py |
Central registry of all measurement-affecting parameters with typed defaults |
baselines.py |
Prompt library management: loading, listing, and appending to prompts.csv |
statistics.py |
Bootstrap confidence intervals, Cohen's d effect sizes, cross-category aggregation |
visualizations.py |
Matplotlib plot generation for all three signal families (returned as base64 PNGs) |
comparative.py |
Cross-prompt comparative visualizations and batch dashboard plots |
dataset.py |
Session management: result accumulation, CSV/JSON persistence, ZIP export packaging, session restore |
reports.py |
PDF report generation via ReportLab |
modules/base.py |
Module framework: TASMModule base class, auto-discovery, parameter metadata, thread-isolated runner |
modules/token_variance.py |
Token variance module: cross-context coupling stability analysis |
modules/probe_generator.py |
Auto-probe generation from model vocabulary per template cell |
modules/correction_heatmap.py |
Domain lattice interaction measurement via inter-layer probe deltas |
modules/correction_manifold.py |
PCA + K-means fingerprint clustering of per-prompt probe projections |
modules/domain_surface.py |
Probe embedding, domain surface mapping, nearest-probe proximity |
modules/comparative_analysis.py |
Cross-prompt aggregate statistics, separability, batch plot coordination |
modules/displacement_field.py |
3D correction field topology data validation and statistics (Three.js viewer) |
modules/mechanistic_interpretability.py |
MI readiness evaluation: AUROC, length confounds, PCA consolidation, random baselines |
modules/mi_instrumentation.py |
MI outputs: refusal direction, activation patching map, per-layer AUROC |
The frontend consists of a single-page HTML application (static/index.html, ~4,180 lines) and a separate chat interface (static/chat.html). All rendering and interaction logic is client-side JavaScript; the server provides a JSON API and serves plot images on demand.
The fundamental operation is weight delta projection. At model load time, TASM downloads the base and instruct variants of a model pair from HuggingFace, then computes the weight delta ΔW = W_instruct − W_base for six projection matrices per transformer layer (Q, K, V, O, gate, up). Base model weights are read directly from safetensors files on disk one tensor at a time, avoiding full base-model instantiation and halving peak memory.
At analysis time, a single forward pass through the instruct model with registered hooks captures hidden states and attention weights at monitored layers. All three signal families are extracted from these cached activations without additional forward passes:
ASM (Alignment Stress Map) computes per-token signed attribution by projecting hidden states through ΔW_V, weighting by attention patterns, and aggregating across signal layers (the middle third of the network). This yields a scalar stress score, per-token attribution vectors, distribution metrics (entropy, top-2 share, interior CV), and — when full trajectory mode is enabled — a layer-by-layer amplitude trace and a token×layer heatmap.
LTP (Lateral Tension Profile) probes the alignment field perpendicular to the generation path. For each token position, it identifies the top-k counterfactual tokens the model considered but did not select, computes unembedding directions for each, and measures the lateral tension (the component of the alignment correction toward each alternative) via ΔW_V projection. This produces per-token ranked tension profiles, profile shape classifications (steep/flat/inverted), PCA-projected dual trajectories (semantic vs. tension), and three summary statistics: M (offset magnitude), V (offset variance), and L (lateral coverage). A fourth statistic, C (offset consistency), was removed after testing showed near-perfect correlation with M.
SFD (Spectral Field Density) measures how many dimensions of the QK routing subspace each token's activation engages. At load time, it SVD-decomposes the concatenated [ΔW_Q; ΔW_K] per layer and caches the right singular vectors. At inference, it projects each token's hidden state through this basis. Energy, spectral entropy, and effective rank are computed internally per token, but only the density ratio (per-token effective rank divided by the layer's global effective rank) is persisted. Prompt-level aggregates (mean, max, variance, p90) of density summarize the dimensionality axis.
Behavioral comparison optionally loads the base model for a separate forward pass to compute KL(instruct ‖ base) divergence at the output distribution and capture top-k next-token predictions from both models. A rank displacement metric compares counterfactual token orderings between base and instruct models.
Single prompt analysis accepts:
-
prompt(string, ≤5,000 characters) — the text to analyze -
category(string) — one ofbenign,mild,harmful,jailbreak,adversarial,dual-use; unrecognized values are mapped tounknown - Boolean flags:
compute_kl,compute_trajectory,capture_responses,full_capture,compute_ltp,compute_sfd - LTP parameters:
ltp_k(counterfactual depth: 4, 6, or 8),ltp_layer_strategy(signalorlate)
Batch analysis accepts a CSV file with columns prompt and category, plus the same boolean and LTP parameter flags applied uniformly to all prompts.
Chat interface accepts a message history (JSON array of {role, content} objects), max_tokens (≤512), and optional analyze/analyze_response flags that trigger ASM/LTP/SFD analysis of the user message and/or the model's generated response.
The model registry (models.json) ships with four Qwen 2.5 pairs (0.5B, 1.5B, 3B, 7B). Custom HuggingFace base/instruct pairs can be added at runtime. The engine auto-detects layer count, attention head configuration, GQA grouping, and hidden dimensionality.
-
prompts.csv— a library of categorized prompts for the sidebar prompt picker and batch analysis
Each analysis produces a PromptResult serialized to a JSON dictionary with the following field groups:
Identity and tokenization: prompt, category, tokens (list of decoded token strings), seq_len
ASM scalars: stress_score (float), net_correction (float), entropy, top2_share, middle_share, interior_cv (all floats, distribution metrics), n_negative_tokens (int), has_negative_tokens (bool)
ASM arrays: per_token_stress (float array, length = seq_len), signed_attr (float array, length = seq_len), amplitude_trajectory (float array, length = 2 × n_layers for attn+MLP sublayers), amplitude_normalized (same shape), heatmap (2D array: sublayers × seq_len)
Behavioral divergence: kl_divergence (float or null), per_token_kl (float array or null), instruct_topk and base_topk (lists of [token_string, probability] pairs, up to 10 each), base_counterfactual_tokens (per-position top-k from base model)
LTP sub-object (ltp): profiles (list of numpy arrays per token), tension_magnitudes (float list), profile_shapes (string list: "steep"/"flat"/"inverted"), counterfactual_tokens (per-position ranked alternatives with probabilities), offset_magnitude/offset_variance/lateral_coverage (per-layer dictionaries), mean_M/mean_V/mean_L (summary scalars), max_prc (peak rank concentration), n_directional (count of tokens with PRC above threshold), semantic_trajectory_2d/tension_trajectory_2d (PCA projections), k, layer_strategy (configuration echo)
SFD sub-object (sfd): per_token_density (float array), 4 prompt-level density aggregates (density_mean/max/var/p90), global_erank, n_layers_monitored, k. Note: per-token energy and entropy are computed internally during the SFD pipeline but only density (the ratio of per-token effective rank to global effective rank) is persisted in the result object.
Rank displacement (rank_displacement): mean_matched, mean_replacement, mean_concentration, mean_tau (Kendall's tau), mean_overlap, per-position detail arrays
Full capture extras (when enabled): per_token_coherence (cross-layer direction agreement), per_token_spectral_rank, attn_frac (attention vs. MLP contribution ratio), token_similarity (token×token cosine similarity matrix)
Each analysis generates up to 12 plot types as base64-encoded PNGs:
ASM plots: signed attribution bar chart, focused stress bar chart, distribution metrics panel, amplitude trajectory line plot, token×layer heatmap.
LTP plots: lateral tension profiles (stacked magnitude), tension magnitude bar chart, dual trajectory (PCA), summary statistics panel, profile heatmap (token × rank).
SFD plots: density bar chart, rank displacement chart.
Summary CSV (summary.csv): one row per analyzed prompt, 33 columns of scalar metrics including all ASM, LTP, SFD, and rank displacement aggregates, plus model prediction summaries and configuration echo fields.
Full results JSON (results.json): complete per-prompt result objects with all per-token arrays, profiles, and trajectories. For 271 prompts with full capture enabled, this file is approximately 17 MB.
Aggregate statistics JSON (aggregate_statistics.json): batch-level computed analytics including per-category bootstrapped means with confidence intervals, pairwise separability (Cohen's d with bootstrap CIs for every metric between category pairs), length-correlation analysis, and cross-metric correlations.
Export ZIP (tasm_session_<timestamp>.zip): configurable archive containing any combination of summary CSV, full results JSON, aggregate statistics JSON, module results (e.g. module_token_variance.json), per-prompt PNG plots, comparative/dashboard plots, and a PDF report.
PDF report (via ReportLab): formatted batch analysis report with summary tables, separability analysis, and embedded visualizations.
All API endpoints return JSON. The single-analysis endpoint returns:
{
"ok": true,
"result": { /* full PromptResult dict */ },
"plot_keys": ["signed_attribution", "stress_per_token", ...],
"session_n": 42,
"cache_size_bytes": 1048576
}Plots are served separately via GET /api/plots/{plot_key} and GET /api/plots/individual/{index}/{plot_key} as PNG files. Plots are generated lazily on first request and cached to disk — they are not pre-generated during dashboard computation.
The server maintains global mutable state (loaded models, activation caches, session data, engine configuration) protected by threading locks: _analysis_lock serializes forward passes and session writes to prevent activation cache corruption; _loading_lock makes model loading state transitions atomic; _plot_gen_lock prevents duplicate lazy plot generation. Batch analysis runs in a background daemon thread, with progress communicated via a shared log list polled by the frontend. Module execution runs in isolated daemon threads with crash protection — a module failure does not affect the main application.
- Language: Python 3.10+
- Framework: FastAPI + Uvicorn
- ML stack: PyTorch, HuggingFace Transformers, Safetensors, Accelerate
- Visualization: Matplotlib
- Statistics: NumPy, SciPy
- Reporting: ReportLab (PDF)
- Compute: CPU by default; GPU optional. The instruct model remains in memory; the base model is loaded on-demand for KL/LTP computation and immediately unloaded afterward.
- Memory: 4–32 GB depending on model scale (0.5B–7B parameters).
TASM measures how instruction-tuning (RLHF, SFT, or similar) changed a language model's internal behavior at inference time, on a per-token basis, for any given prompt. It does this by comparing the weights of an instruction-tuned model against its base (pre-training-only) counterpart and projecting activations through the difference.
The pipeline has three signal families — ASM, LTP, and SFD — plus a rank displacement instrument (RD) that answer four different questions about the alignment correction at each token:
- ASM (Alignment Stress Map): How hard is the alignment correction pushing?
- LTP (Lateral Tension Profile): In which direction is the alignment correction structured?
- SFD (Spectral Field Density): How many dimensions of the alignment correction does each token engage?
- RD (Rank Displacement): How much did alignment training change the set and ordering of candidate tokens?
There are also several supporting computations: behavioral divergence (KL), candidate graph topology, and batch-level statistical aggregation. Token Variance analysis operates post-hoc on session data via the module framework (see Part 4). This document traces every mathematical operation from model loading through to final statistics.
Before analyzing any prompts, TASM computes the difference between the instruction-tuned model's weights and the base model's weights. This difference — the "delta" — represents everything that alignment training changed. If the base model has weights W_base and the instruct model has weights W_instruct, the delta is simply:
ΔW = W_instruct − W_base
TASM computes this for six projection matrices in every transformer layer: the query (q_proj), key (k_proj), value (v_proj), output (o_proj), gate (gate_proj), and up (up_proj) projections. These are the linear transformations inside attention and MLP sublayers — the parts of the network where alignment training has the most direct geometric effect.
Not all layers are equally important. TASM designates the middle third of the network as the "signal layers." For a 24-layer model, layers 8–15 are the signal layers. This is where prior work suggests alignment corrections are most active — deep enough to have built semantic representations, but before the network commits to a specific output token. The fraction is configurable via the signal_layer_fraction parameter (default 0.333):
frac = signal_layer_fraction
mid_start = floor(n_layers × frac)
mid_end = floor(n_layers × (1 − frac))
signal_layers = [mid_start, mid_start+1, ..., mid_end−1]
For every delta matrix, TASM also stores its Frobenius norm — the square root of the sum of all squared entries. This acts as a normalization constant later on:
‖ΔW‖_F = √(Σᵢⱼ ΔWᵢⱼ²)
At load time, TASM also computes the spectral structure of each delta matrix via truncated SVD. For each ΔW, it computes the top singular values σ₁ ≥ σ₂ ≥ ... ≥ σ_k (where k is configurable via delta_svd_k, default 64), normalizes them into a probability distribution:
pᵢ = σᵢ / Σⱼ σⱼ
and then computes the effective rank as the exponential of the Shannon entropy of this distribution:
effective_rank = exp(−Σᵢ pᵢ log pᵢ)
If the delta is dominated by a single direction (σ₁ ≫ σ₂), effective rank ≈ 1 — alignment training made a surgical correction. If the singular values are spread out, effective rank is high — alignment reshuffled the entire subspace. TASM also records the fraction of total spectral energy (Σ σᵢ²) captured by the top-1 and top-5 singular values. These are aggregate diagnostics reported at the model level; they cost nothing per prompt.
For each prompt, TASM tokenizes it and runs a single forward pass through the instruct model. During this pass, forward hooks capture:
-
Hidden states
hat the input-layernorm of each monitored layer. These are the residual stream representations entering each transformer block — the activations that get projected through the attention and MLP sublayers. Shape:(1, seq_len, hidden_dim). -
Attention weights
αat each monitored layer's self-attention module. These are the post-softmax attention matrices that determine how much each position attends to every other position. Shape:(1, n_heads, seq_len, seq_len).
When full trajectory mode is enabled, hidden states are captured at every layer (not just signal layers) at both the input-layernorm (pre-attention) and post-attention-layernorm (pre-MLP) positions, giving a sublayer-by-sublayer picture of how the residual stream evolves.
This is the core ASM computation. For each signal layer, it answers: "For each token in the input, how much is that token contributing to the alignment correction, and in which direction?"
Step 1: Project hidden states through the value delta.
Take the hidden state h (shape: seq_len × hidden_dim) and multiply by the transpose of the V-projection delta:
v = h · ΔW_V^T
This gives v with shape (seq_len, v_proj_out_dim). Each row is the "correction potential" — how much each token would be corrected if it were the only thing going through this sublayer.
Step 2: Reshape for grouped-query attention (GQA).
The v-projection output is reshaped to (seq_len, n_kv_heads, head_dim), because in GQA architectures, multiple query heads share the same KV head. Attention weights are similarly regrouped by averaging across the query heads that share each KV group:
α_kv[g] = mean over q-heads in group g of α[q]
Step 3: Compute the per-head correction direction.
For each KV head g, the attention-weighted correction is:
δ[g] = α_kv[g] · v_heads[:, g, :]
This is a (seq_len, head_dim) matrix. Row i is the correction vector at position i for this head — a sum of correction potentials from all positions, weighted by how much position i attends to them.
Step 4: Compute the unit correction direction.
Normalize the correction vector at the final position to get a unit vector:
û = δ[-1] / ‖δ[-1]‖
This unit vector points in the direction the alignment correction is pushing at the output position.
Step 5: Project correction potentials onto this direction.
For each source token j, compute how much of its correction potential aligns with the overall correction direction:
proj[j] = û · v_heads[j, g, :]
Then the signed attribution for token j is:
signed_attr[j] = α[-1, j] × proj[j]
where α[-1, j] is how much the output position attends to position j. The sign matters: positive means the token pushes with the correction, negative means it pushes against it.
Step 6: Verify exactness (Proof 1).
The sum of signed attributions across all tokens should exactly equal the norm of the correction vector:
Σⱼ signed_attr[j] = ‖δ[-1]‖
This is checked per-head and reported. It's a mathematical identity (the projection decomposes the norm), so errors above the configurable proof1_threshold (default 10⁻⁴) indicate numerical issues.
Step 7: Aggregate across heads and layers.
Per-head signed attributions are averaged across KV heads within each layer, then averaged across signal layers, yielding a single signed attribution value per token.
final_signed_attr[j] = mean over layers L of (mean over heads g of signed_attr_L,g[j])
From the averaged signed attribution vector, TASM computes several statistics that characterize how the correction is distributed across tokens:
Net correction: The sum of all signed attributions. This is positive when the overall correction pushes in a consistent direction; close to zero when positive and negative contributions cancel.
Normalized entropy: Take absolute values of attributions, normalize to a probability distribution, and compute Shannon entropy relative to maximum possible entropy (log of sequence length):
dᵢ = |attr[i]| / Σⱼ |attr[j]|
H = −Σᵢ dᵢ log dᵢ
entropy = H / log(seq_len)
Values near 1 mean the correction is spread uniformly across tokens; values near 0 mean it's concentrated on a few tokens.
Boundary vs. interior split: The prompt is divided into boundary tokens (the first and last portion of the sequence, configurable via boundary_fraction, default 10%, minimum 1 token each) and interior tokens (everything in between). top2_share is the fraction of total absolute attribution at boundary positions. middle_share is the fraction at interior positions. interior_cv is the coefficient of variation (standard deviation ÷ mean) of the interior attribution values.
The hypothesis: benign prompts concentrate correction at the boundaries (system prompt, instruction tokens), while adversarial prompts distribute correction into the interior.
The stress score measures how strongly the alignment delta responds to the prompt's activations, normalized by the delta's own scale. For each signal layer, and for each of the three attention projections (Q, K, V):
projected = h · ΔW^T (shape: seq_len × proj_dim)
per_token_norm = ‖projected‖₂ (along the projection dimension)
normalized = per_token_norm / ‖ΔW‖_F
The per-token stress at this layer is the average of the normalized norms across Q, K, and V projections. The final per-token stress is then averaged across signal layers, and the stress score is the mean across tokens.
In plain language: if a token's hidden state happens to lie in the subspace that alignment training modified most, the projection through ΔW will be large. Dividing by the Frobenius norm of ΔW makes this comparable across projections and layers. A high stress score means the prompt's representation happens to strongly "engage" the directions that alignment training cared about.
When full trajectory mode is enabled, TASM computes the stress at every sublayer in the entire network (not just signal layers), for both attention and MLP blocks. At each sublayer:
- For attention: project
hthrough the Q, K, and V deltas. - For MLP: project
hthrough the gate and up deltas. - Record both the raw projection norm (unnormalized) and the Frobenius-normalized version.
- Record the per-token normalized norms as a row of the heatmap.
This produces three outputs: a raw trajectory (amplitude at each sublayer), a normalized trajectory (Frobenius-normalized), and a heatmap (sublayer × token matrix of normalized projection norms). The heatmap shows where in the network each token's representation interacts most with the alignment delta.
When full capture is enabled, TASM derives four additional per-token metrics from the heatmap:
Attention fraction: For each token, the fraction of total correction energy coming from attention sublayers vs. MLP sublayers. Attention sublayers are the even-indexed rows of the heatmap; MLP sublayers are the odd-indexed rows.
attn_frac[t] = Σ(attn_rows[:, t]) / (Σ(attn_rows[:, t]) + Σ(mlp_rows[:, t]))
Per-token coherence: How concentrated the correction is across sublayers. For each token, take its column of the heatmap (its correction norm at every sublayer), normalize to a distribution, and compute 1 − normalized_entropy. A value near 1 means all correction happens at a few sublayers (consistent strategy); near 0 means it's spread uniformly.
Per-token spectral rank: The effective dimensionality of each token's correction pattern. Same exponential-of-entropy formula as the delta spectral rank, but applied to the heatmap column for each token.
Token similarity matrix: Cosine similarity between every pair of tokens' correction profiles (their heatmap columns). This shows which tokens receive similar correction patterns from the network.
The LTP probes the alignment field in directions perpendicular to the generation path. Where ASM measures intensity on the path the model took, LTP measures the structure of the field surrounding that path. Two prompts can have identical ASM amplitude but very different LTP signatures if one runs through the center of a broad high-correction region (robust) and the other runs along a boundary (fragile).
At each token position, TASM identifies the top-k alternative tokens the model considered but did not select. From the instruct model's logit output at position i:
top_k_alternatives = top-k tokens from softmax(logits[i]) excluding the actual token
Default k=8. If the base model is loaded, TASM also independently selects the base model's top-k alternatives at each position (these may differ from the instruct model's alternatives).
At each token position i, the "forward direction" τ is defined as the normalized difference between consecutive hidden states at the first monitored layer:
τ[i] = (h[i] − h[i−1]) / ‖h[i] − h[i−1]‖
This approximates the direction the model's residual stream is "moving" through representation space at that position. For the first token, it uses h[1] − h[0] instead.
For each counterfactual token c at position i, TASM constructs a "probing direction" in the output vocabulary space:
d_ic = W_u[c] − W_u[chosen_i]
where W_u is the unembedding matrix (the lm_head weight). This is the direction in embedding space that points from the token the model chose toward the alternative it didn't choose.
This probing direction then goes through a three-step projection pipeline:
Step 1: Project through half the V-delta.
Δv = (ΔW_V / 2) · d_ic
The factor of ½ represents the midpoint of the alignment correction — conceptually, the "average" position between the base and instruct models' value projections.
Step 2: Reshape and expand through the output projection.
The projected vector is reshaped to (n_kv_heads, head_dim), expanded for GQA (repeating shared KV head outputs for each query head that uses them), flattened back to the full hidden dimension, and then projected through the output projection matrix:
proj = W_O · expand(reshape(Δv))
This gives a vector in the residual stream's coordinate system — the correction that would be applied.
Step 3: Decompose into forward and lateral components.
forward_component = (proj · τ) × τ
lateral_component = proj − forward_component
lateral_magnitude = ‖lateral_component‖
The lateral component is the part of the correction that pushes perpendicular to the model's generation direction. A large lateral magnitude means the alignment field is structured to pull the representation sideways — toward or away from this alternative — rather than just speeding up or slowing down along the current path.
At each token position, the lateral magnitudes for all k alternatives (sorted by the model's probability ranking) form the lateral tension profile — a k-dimensional vector where entry j is how much lateral pull the j-th most-likely alternative token exerts.
This computation happens at every monitored layer, and the profiles are averaged across layers to produce a single profile per token.
Each token's averaged profile is classified into one of three shapes:
-
Steep: The top-ranked alternative dominates (>40% of total magnitude, and at least 2× the second-ranked). This means the alignment correction is concentrated toward one specific alternative — a focused boundary.
-
Inverted: The second half of the profile has higher mean magnitude than the first half (by >30%). Lower-ranked alternatives exert more pull than higher-ranked ones — an anomalous pattern that suggests the alignment field's geometry doesn't align with the model's probability ranking.
-
Flat: Neither steep nor inverted. The lateral tension is spread across alternatives without strong directional preference.
For each position, TASM also computes a probability-weighted average of the lateral vectors:
tension_point = (Σ_c prob_c × lateral_vector_c) / Σ_c prob_c
This is a single vector in hidden-state space representing the net lateral pull, weighted by how likely each alternative was. This is averaged across monitored layers.
From the per-layer tension points, TASM computes three summary statistics at each monitored layer, then averages across layers:
M — Offset Magnitude: The norm of the mean tension point across active positions (tokens where tension is non-zero). This measures how large the net lateral displacement is.
mean_offset = mean of tension_points across active positions
M = ‖mean_offset‖
V — Offset Variance: The variance of individual tension magnitudes across positions. High V means the lateral pull is concentrated at specific tokens rather than evenly distributed.
L — Lateral Coverage: The fraction of tokens that have any non-zero lateral tension at all.
C — Offset Consistency (removed): An earlier revision computed C as the ratio of the mean offset's magnitude to the average individual magnitude (C = M / mean(‖tension_point_i‖)). This was removed because it proved nearly perfectly correlated with M (r=0.989), providing no additional information.
The diagnostic hypothesis: High M = "boundary-threading signature" — the prompt is consistently pulled in one lateral direction at every position, suggesting it runs along a systematic alignment boundary.
Two optional enhancements were explored during development and subsequently removed after literature review determined they were inappropriate for cross-model weight delta projection:
SVD Truncation (removed): Projecting through a rank-r truncation of ΔW_V to isolate a "dominant safety subspace." Ponkshe et al. (2025) showed that top SVD directions of alignment deltas capture general parameter sensitivity rather than safety-specific directions. The full-rank ΔW_V is used for all computations. The code path remains dormant.
Tuned-Lens Correction (removed): Applying per-layer affine transforms trained on a single model's representational drift to calibrate unembedding probes at intermediate layers. The tuned lens (Belrose et al., 2023) is a within-model state decoder; applying it to vectors produced by cross-model weight delta projection is geometrically incoherent. The code path remains dormant.
For each token, TASM computes how concentrated the profile is toward the top-ranked alternative:
normalized_profile = profile / sum(profile)
PRC = max(normalized_profile) − 1/k
PRC = 0 means the profile is perfectly flat (uniform across alternatives). PRC > 0 means one alternative dominates. Tokens with PRC above a threshold (0.02) are counted as "directional" — they have a meaningful geometric preference.
For visualization, TASM projects both the semantic trajectory (raw hidden states h[0], h[1], ..., h[T]) and the tension trajectory (hidden states plus tension points: h[i] + tension_point[i]) into a shared 2D space via PCA. The procedure:
- Stack the semantic and tension trajectories into a single matrix:
[h₁...h_T ; (h₁+t₁)...(h_T+t_T)] - Mean-center the combined matrix.
- Compute SVD:
U · Σ · V^T - Project all points onto the first two right-singular vectors (the two directions of greatest variance).
The result is two 2D curves. Their separation shows how much and how consistently the alignment correction displaces the representation path.
When the base model is loaded, TASM repeats the lateral tension computation using the base model's top-k alternatives (instead of the instruct model's) as the probing directions. Everything else — the ΔW_V/2, the hidden states, the forward direction — stays the same. This produces a "base bank" profile at each position that shows the lateral structure from the base model's perspective, enabling comparison of how the two models "see" the nearby counterfactual landscape.
SFD measures how many dimensions of the alignment-reshaped QK routing subspace each token's activation engages. Where ASM measures intensity and LTP measures directional structure, SFD measures dimensionality.
For each monitored layer, TASM concatenates the Q and K projection deltas vertically:
ΔW_QK = [ΔW_Q ; ΔW_K] (stacked along the output dimension)
This concatenated matrix represents the combined "routing topology" that alignment training reshaped — how the model decides which tokens attend to which other tokens.
TASM performs truncated SVD on this concatenated delta:
ΔW_QK ≈ U · diag(σ₁..σ_k) · V_k^T
The number of components k is configurable via sfd_svd_k (default 16). The layer range defaults to layers 9–15 but can be configured via sfd_layer_start/sfd_layer_end, or set to match the ASM signal layers via the sfd_use_signal_layers flag. All three parameters are accessible in the Advanced Parameters panel.
The right singular vectors V_k (shape: k × hidden_dim) define the k most important directions in the input space that alignment training modified for routing purposes. The singular values σ₁..σ_k quantify how much each direction was modified.
TASM also computes per-layer global measures from the singular value spectrum: effective rank (same exp-entropy formula), spectral entropy, log-volume (sum of log singular values), stable rank (‖ΔW_QK‖²_F / σ₁²), and Frobenius norm.
For each token at each monitored layer, the activation vector h is projected into the cached subspace:
c = V_k · h (k-dimensional coefficient vector)
w = σ ⊙ c (elementwise weighting by singular values)
The coefficient vector c tells you how much of the activation lies along each alignment-modified direction. Weighting by σ emphasizes the directions that alignment training changed most.
From this weighted projection, three measures are computed:
Energy: The squared norm of the weighted projection — total activation energy in the alignment subspace.
energy = ‖w‖² = Σᵢ (σᵢ · cᵢ)²
Spectral entropy: How evenly the energy is distributed across the k directions.
qᵢ = wᵢ² / energy (normalized energy distribution)
H_t = −Σᵢ qᵢ log qᵢ
Effective rank of the token:
erank_t = exp(H_t)
Density ratio: The token's effective rank divided by the layer's global effective rank. Values > 1 mean the token engages more dimensions of the alignment subspace than average; values < 1 mean it engages fewer.
density = erank_t / erank_global
Per-token energy, entropy, and density measures are averaged across monitored layers internally. However, only the density ratio is persisted in the result object. The prompt-level output includes four density statistics: mean, max, variance, and 90th percentile.
When the base model is loaded, TASM computes the KL divergence from the instruct model's output distribution to the base model's at each token position:
KL(instruct ‖ base)[i] = Σ_v p_instruct(v|i) × (log p_instruct(v|i) − log p_base(v|i))
where the sum is over the entire vocabulary. This is computed exactly (no sampling) from the full logit vectors. The headline number is the KL at the final position (the next-token prediction), but per-token KL is stored for the full sequence.
TASM captures the top-k (default 10) most probable next tokens and their softmax probabilities from both the instruct and base models. These are human-readable diagnostic outputs: they show what each model would actually generate.
Rank displacement compares how the instruct and base models order the same set of counterfactual alternatives at each token position. It decomposes the displacement into three pools:
Matched: Tokens that appear in both models' top-k. Displacement = absolute difference in probabilities between the two models.
Promoted: Tokens that appear only in the instruct model's top-k. These are alternatives that instruction-tuning elevated into consideration. Displacement = the instruct probability (full value, since the base model didn't rank them highly enough to appear).
Demoted: Tokens that appear only in the base model's top-k. These are alternatives that instruction-tuning suppressed. Displacement = the base probability.
At each position, total displacement is the sum of all three pools:
total_disp = matched_disp + promoted_mass + demoted_mass
replacement_ratio = (promoted_mass + demoted_mass) / total_disp
A high replacement ratio means the instruct and base models consider largely different alternatives — alignment training didn't just re-rank candidates, it replaced them entirely.
Legacy metrics: For backward compatibility, TASM also computes Kendall's τ (rank correlation) and Jaccard overlap between the shared tokens' rankings. Kendall's τ is computed at every position where at least 2 tokens appear in both models' top-k (configurable via rd_min_shared, default 2). Positions with fewer than 2 shared candidates receive τ = 0.0. The per_position_tau array is always the same length as the tokens array — every position gets a value.
This is a post-hoc analysis of the counterfactual candidate sets. For each prompt, TASM builds a graph of all unique candidate tokens across all positions, tracking which positions each candidate appears at and whether it was promoted, demoted, or matched at each.
Key metrics:
- Contested fraction: How many positions have both promotions and demotions (the instruct model is actively reshuffling alternatives, not just ignoring them).
- Dual-role candidates: How many unique tokens appear as promoted at some positions and demoted at others.
- Role switches: How many times a candidate's status changes between adjacent positions (promoted → demoted or vice versa).
- Switch rate: Role switches per position.
When multiple prompts have been analyzed, TASM computes aggregate statistics across the full set.
Results are grouped by category (benign, harmful, jailbreak, etc.). For each category and each metric in the registry (15 metrics spanning ASM, KL, LTP, SFD, and rank displacement), TASM computes a bootstrap confidence interval (configurable: n_bootstrap resamples, default 5,000; ci_level, default 0.95):
- Draw a sample with replacement of the same size as the group.
- Compute the mean of the sample.
- Repeat for n_bootstrap iterations.
- The estimate is the mean of the original data; the CI bounds are the α/2 and (1−α/2) percentiles of the bootstrap distribution.
The seed is fixed at 42 for reproducibility.
For each pair of (benign-ish category, target category), TASM computes Cohen's d — the standardized mean difference — for every metric:
d = |mean_A − mean_B| / s_pooled
where s_pooled = √((s_A² + s_B²) / 2)
Cohen's d is also bootstrapped (5,000 resamples, same procedure but resampling both groups independently in each iteration) to get confidence intervals on the effect size itself.
For each metric and each benign-vs-target pair, TASM does a brute-force threshold sweep (configurable via threshold_steps, default 500 evenly-spaced candidate thresholds between the min and max observed values). At each threshold, it evaluates accuracy in both directions ("harmful ≥ threshold" and "harmful < threshold") and reports the threshold, accuracy, and direction that maximizes classification accuracy.
Stress vs. KL correlation: Pearson r between stress_score and kl_divergence across all prompts that have both. This tests whether the structural signal (how much the delta responds) correlates with the behavioral signal (how different the output distributions are).
Length correlations: For every metric, Pearson r between the metric value and sequence length. This is a diagnostic for measurement artifacts — if a metric correlates with length, it may be measuring tokenization effects rather than alignment signal.
| Symbol | Meaning |
|---|---|
h |
Hidden state (residual stream activation) at a given layer |
ΔW_V |
Value projection weight delta (instruct − base) |
ΔW_Q, ΔW_K
|
Query and key projection weight deltas |
α |
Attention weight matrix (post-softmax) |
W_O |
Output projection weight (from the instruct model) |
W_u |
Unembedding matrix (lm_head weight) |
τ |
Forward direction (normalized consecutive hidden-state difference) |
d_ic |
Unembedding probing direction (alternative token − chosen token) |
V_k |
Top-k right singular vectors of the concatenated QK delta |
σ |
Singular values |
seq_len |
Number of tokens in the input |
n_layers |
Total transformer layers in the model |
n_kv_heads |
Number of key/value heads (GQA) |
head_dim |
Dimension per attention head |
hidden_dim |
Full hidden state dimension (n_heads × head_dim) |
TASM's visualization system operates across three rendering layers: server-side Matplotlib plots (rendered to base64 PNGs), client-side JavaScript-rendered interactive components, and a client-side Three.js WebGL 3D terrain viewer. All visuals share a unified dark theme based on Material Design's #121212 surface with an Okabe-Ito colorblind-safe palette, following Tufte-inspired data-ink ratio principles.
This section covers every visualization in the system, organized by scope (single prompt vs. batch) and signal family (ASM, LTP, SFD), with attention to the design language, the data each visualization encodes, and the rendering mechanics.
TASM uses the Okabe-Ito palette, recommended by Nature Methods for categorical scientific data. It is designed to be distinguishable by people with all common forms of color vision deficiency:
| Category | Color | Hex | Role |
|---|---|---|---|
| Benign | Blue | #0072B2 | Safe/baseline prompts |
| Mild | Amber | #E69F00 | Low-risk prompts |
| Harmful | Vermillion | #D55E00 | Dangerous prompts |
| Jailbreak | Reddish purple | #CC79A7 | Adversarial attacks |
| Adversarial | Reddish purple | #CC79A7 | Same hue as jailbreak |
Marker shapes provide redundant encoding for accessibility: benign = circle, mild = square, harmful = diamond, jailbreak = triangle-up.
Profile shape classifications use their own color subset: steep = amber (#E69F00), flat = sky blue (#56B4E9), inverted = vermillion (#D55E00).
The background hierarchy follows Material Design elevation:
| Surface | Hex | Usage |
|---|---|---|
| #121212 | Figure and page background (not pure black — prevents OLED bleed) | |
| #1E1E1E | Axes/panel background (one elevation step up) | |
| #252525 | Card/legend background |
Text uses three opacity tiers of white: primary (#DEE2E6, 87%), secondary (#9CA3AF, 60%), and muted (#6B7280, 38%). Grid lines are #333333 at 30% opacity. Axis spines are #404040. This hierarchy keeps data prominent while providing structural context without visual competition.
The TASM sequential colormap progresses through: dark background → deep blue → teal → light blue → yellow-green → amber → vermillion. This is a custom 8-stop map designed to be perceptually uniform in the dark theme context while avoiding problematic green-red transitions.
All plots apply a shared set of 22 RC parameter overrides at import time. Key choices: top and right spines are removed (Tufte: maximize data-ink ratio), grid lines are thin (0.5pt) and barely visible (30% alpha), all text is minimum 12-13pt, figure DPI is 200 for sharp rendering on retina displays, and the font stack is Arial → Helvetica → DejaVu Sans.
All Matplotlib plots follow the same lifecycle: create figure → render content → call fig_to_base64() → close figure. The function writes the figure to a BytesIO buffer as PNG with tight bounding box, encodes to base64, and closes the figure to free memory. The base64 string is stored in the session (for individual prompt plots) or served directly to the frontend (for dashboard plots). On export, base64 strings are decoded back to PNG files for inclusion in the ZIP archive.
These are generated per prompt analysis, organized into four categories in the frontend: ASM Core (3 plots), ASM Detail (2 JS-rendered components), LTP (3 plots), SFD (2 plots). Each has a scope of "prompt" and renders server-side unless marked as type "js." Additional LTP JS components (counterfactual table) and LTP plots (dual trajectory, profile heatmap, summary stats) are also generated but may be displayed separately from the main visualization groups.
Signed Attribution Bar Chart (signed_attribution)
A vertical bar chart with one bar per input token. Positive bars are green (#009E73), negative bars are vermillion (#D55E00). The zero line is drawn as a thin gray horizontal rule. Token labels are rotated 50° along the x-axis.
An annotation box in the upper-right corner reports the net correction (sum of all attributions) and the count of negative tokens. The figure width scales linearly with token count (0.65 inches per token, minimum 9 inches) to prevent label crowding on long prompts.
This is the primary diagnostic view for a single prompt: it shows at a glance which tokens drive the alignment correction and whether any tokens push against it.
Per-Token Stress Bar Chart (stress_per_token)
A uniform-color (sky blue, #56B4E9) vertical bar chart showing the focused stress score at each token position. Same adaptive width as the attribution chart. An annotation shows the mean stress score.
Where signed attribution shows direction, this shows magnitude — how strongly the alignment delta responds to each token's representation, regardless of sign. The two views are complementary: a token with high stress but low signed attribution is engaging the alignment subspace without contributing net correction at the output position.
Token × Layer Heatmap (heatmap)
A 2D image plot with tokens on the x-axis and sublayer depth on the y-axis, using the TASM sequential colormap. The y-axis is labeled with four landmarks: Early, Mid (⅓), Late (⅔), and Final. A colorbar on the right shows the normalized sensitivity scale.
This is the most information-dense single-prompt visualization. Boundary-concentrated correction (bright columns at edges, dark in the middle) is the expected benign signature. Interior-distributed correction (bright columns at unexpected positions, or horizontal bright bands at specific depths) may indicate adversarial patterns. The heatmap also reveals which network depths contribute most to the correction — middle-layer attention peaks are the canonical safety-relevant signal.
Attribution Table (token_table, type: js)
An HTML table rendered client-side from the raw per-token data. Each row shows: token text, signed attribution value (colored green or red), a proportional-width bar showing relative attribution magnitude, stress score, and a proportional-width bar showing relative stress magnitude.
Bars are normalized within-prompt: the maximum absolute attribution sets the scale for attribution bars, and the maximum stress sets the scale for stress bars. This allows visual comparison of tokens within a single prompt but not across prompts.
The component is wrapped in a collapsible "feature" container with a header describing what the table shows and a legend explaining the encoding.
Model Predictions (model_predictions, type: js)
Rendered client-side when response capture is enabled. Shows the instruct model's and base model's top-k next-token predictions side by side, with token text and probability for each. This is a direct behavioral readout — what each model would actually generate next.
Lateral Tension Profiles — Stacked Bar (ltp_profiles)
A stacked bar chart where each bar is a token position and the segments within each bar represent the k counterfactual alternatives (default k=8), ordered by the instruct model's probability ranking. Segment heights encode lateral tension magnitude. Colors use the viridis colormap sampled at k evenly-spaced points from 0.2 to 0.95.
Above each bar, non-flat profile shapes are annotated with small markers: upward triangles (^) for steep profiles (amber), downward triangles (v) for inverted profiles (vermillion). Flat profiles get no marker. Only the first 4 ranks are labeled in the legend to avoid clutter.
This is the primary LTP diagnostic: you can see at a glance which tokens have strong lateral tension, how that tension is distributed across alternatives (steep = concentrated on one alternative, flat = spread evenly), and where anomalous inverted profiles occur.
Lateral Tension Magnitude Bar Chart (ltp_tension_magnitudes)
A bar chart of the net tension point magnitude at each token position. Unlike the stacked profiles (which show per-alternative structure), this shows the resultant vector magnitude — how much net lateral pull exists after probability-weighted averaging of all counterfactual directions.
Bars are colored by profile shape classification: amber for steep, sky blue for flat, vermillion for inverted. A dashed horizontal line shows the mean magnitude. An annotation reports the numeric mean. A three-patch legend identifies the shape colors.
LTP Summary Statistics (ltp_summary_stats)
Two horizontal bar panels showing the prompt's M and V statistics. Very small values (< 0.001) switch to scientific notation in the label. C (consistency) is excluded because it is nearly perfectly correlated with M (r=0.989). L (coverage) is excluded because it is consistently 1.0 — every token has non-zero lateral tension, so the metric conveys no information.
LTP Profile Heatmap (ltp_profile_heatmap)
A 2D image plot with tokens on the y-axis and counterfactual rank on the x-axis. Uses the TASM sequential colormap. Columns are labeled R1 through Rk. This is the LTP analog of the ASM heatmap — a dense view that reveals patterns invisible in the bar charts.
Look for: vertical bright columns (one alternative consistently dominates across all tokens), horizontal bright rows (specific tokens with unusually high tension), and diagonal patterns (rank-position correlations that suggest systematic lateral structure).
Per-Token QK Density (sfd_density)
Bar chart (amber, #E69F00) showing the density ratio at each token — how many dimensions of the QK routing subspace the token's activation engages relative to the global effective rank. Values above 1.0 mean the token engages more dimensions than average. An annotation shows mean, max, and global erank.
Rank Displacement (rank_displacement)
Bar chart of per-position Kendall's τ between the base and instruct models' counterfactual alternative rankings. Bars are color-coded by agreement level: green (τ > 0.5, models agree), amber (0 < τ ≤ 0.5, weak agreement), vermillion (τ ≤ 0, models disagree or rank inversely). Horizontal reference lines at 0 (no correlation) and 1 (perfect agreement). Y-axis is fixed at [-1.1, 1.1].
An annotation reports mean τ, mean overlap percentage, and the count of comparable positions out of total positions. Kendall's τ is computed at positions where at least 2 candidates appear in both models' top-k (configurable via rd_min_shared). Positions with fewer shared candidates receive τ = 0.0. The per_position_tau array is always position-aligned with the tokens array.
These are generated when a plot is first requested after batch analysis. The dashboard endpoint returns aggregate statistics and a list of available plot keys instantly — no matplotlib generation occurs during Refresh Dashboard. Individual plots are generated lazily on first request via GET /api/plots/{key}, cached to disk as PNG files, and served from cache on subsequent requests. A generation lock prevents duplicate work on concurrent requests. The frontend shows "Loading {key}.png…" while a plot generates.
Plots are organized into "proven" (Analysis tab) and "experimental" categories. They operate on the full collection of prompt results.
Effect Sizes — Forest Plot (separability)
A horizontal forest plot showing Cohen's d for each proven metric (net correction, interior share, boundary share, entropy, stress score, interior CV), sorted by effect size magnitude descending.
Each metric gets: a point estimate dot (sized for emphasis), a horizontal CI whisker line, and a right-aligned label showing d = X.XX YY%. Dots and whiskers are colored by effect size tier: green for large (d ≥ 0.8), amber for medium (d ≥ 0.5), vermillion for small (d < 0.5).
Vertical reference lines are drawn at d = 0.5 (medium, dashed) and d = 0.8 (large, dotted). The zero line is also drawn for reference. Y-axis is inverted so the strongest effects appear at the top. The left spine is removed for a cleaner look.
Category Distributions — Strip Plot (batch_summary)
Four side-by-side panels (net correction, interior share, stress score, entropy) showing per-category distributions as jittered strip plots with mean markers and CI bars. This replaces traditional box plots following Allen et al. (2021) guidance that strip plots better convey individual data points and avoid the misleading quartile summaries box plots provide at small n.
For each category in each panel: small transparent dots are scattered at jittered x-positions (the jitter is seeded deterministically per category-metric pair). Strip points are synthetically generated from the bootstrap CI parameters (normal distribution centered at the estimate with spread = CI width / 3.5) when the original raw values aren't available in the aggregate. A large opaque circle with a white border marks the mean estimate. A thick vertical line through the mean shows the 95% bootstrap CI.
Separability Scatters (key_scatters)
A two-panel scatter plot: entropy vs. net correction (left) and stress score vs. net correction (right). Points are colored by category and shaped by category marker (redundant encoding). Each category with n ≥ 3 gets a 95% confidence ellipse overlay.
The ellipses are computed from the 2×2 covariance matrix of the two plotted variables. The eigendecomposition gives the principal axes; the semi-axis lengths are scaled by √(χ²₂(0.95) × λ) = √(5.991 × eigenvalue). This is the standard bivariate-normal 95% containment ellipse. For non-normal data it's an approximation, but it still provides a useful visual summary of each group's location and spread.
Proof 1 Verification (proof1_summary)
Two-panel diagnostic. Left panel: histogram of log₁₀(error) across all proof-1 exactness checks from all prompts and heads. Right panel: two bars showing the exact (error < proof1_threshold, default 10⁻⁴) and inexact fractions, with percentage labels.
This is a computational integrity check, not a statistical inference — it validates that the mathematical decomposition (signed attribution sums to the correction norm) is numerically exact to machine precision.
Trajectory Overlay (exp_trajectory_overlay)
All prompts' normalized amplitude trajectories superimposed on a single plot, each colored by category. Vertical dashed lines mark the early→mid and mid→late transitions. Category legend included.
This is a raw exploratory view — no aggregation or smoothing. If categories cluster into different trajectory shapes (e.g., adversarial prompts peaking earlier or higher), it's visible immediately. But with many prompts, visual overplotting can obscure patterns.
Difference from Benign Baseline (exp_difference_from_benign)
For each non-benign category, the mean trajectory is computed and the benign mean trajectory is subtracted. The resulting difference curves are plotted with fill-between shading. This isolates where each category deviates from baseline at each network depth.
Discriminative Sublayers (exp_discriminative_sublayers)
A horizontal bar chart ranking the top-15 sublayers by their adversarial-minus-benign amplitude difference. Each bar is labeled with its layer number, sublayer type (Attn or MLP), and network region (Early/Middle/Late). Colors encode region: green for early, reddish purple for middle, sky blue for late.
Full Scatter Grid (exp_metric_scatters)
A 2×3 grid of scatter plots showing five pairwise metric combinations (stress vs. KL, entropy vs. net correction, boundary vs. interior share, stress vs. net correction, entropy vs. stress). The sixth cell is empty. Points colored by category. This is the exhaustive view — it includes weak and redundant metric pairs that the proven scatter panel omits.
Behavioral Comparison (exp_behavioral_comparison)
A grouped bar chart with one group per prompt showing the instruct model's and base model's top-1 next-token probabilities side by side (sky blue for instruct, vermillion for base). Prompt labels are truncated and word-wrapped. The gap between paired bars shows behavioral divergence.
LTP Category Comparison (exp_ltp_category_comparison)
Three side-by-side box plots (offset magnitude, offset consistency, offset variance) with one box per category. Standard Tukey box plots with IQR boxes, median lines, 1.5×IQR whiskers, and outlier points. Boxes are colored by category and drawn at 75% opacity.
LTP M vs. Stress (exp_ltp_m_vs_stress)
Scatter plot of LTP offset magnitude (y) against ASM stress score (x), points colored by category. Tests whether LTP captures information orthogonal to ASM — prompts that separate on M but not on stress validate the framework's claim that directional structure carries signal beyond amplitude.
Profile Shape Distribution (exp_ltp_profile_shapes)
A grouped bar chart showing the fraction of tokens classified as steep, flat, or inverted, for each category. Each category gets three bars (one per shape). Colors match the shape palette.
SFD Category Comparison (exp_sfd_category_comparison)
Three box plots (QK density, spectral entropy, QK energy) by category. Same Tukey box plot format as the LTP comparison.
SFD vs. ASM (exp_sfd_vs_asm)
Scatter of SFD QK density against ASM interior share, colored by category. Tests whether the SFD dimensionality axis provides orthogonal information to the ASM distributional metrics.
Rank Displacement by Category (exp_rank_displacement)
Two box plots (Kendall τ, token overlap) by category. Shows whether the degree of base-vs-instruct counterfactual reshuffling varies systematically by prompt type.
The most complex visualization is a client-side Three.js 3D terrain that renders per-prompt probability displacement between the base and instruct models' counterfactual candidate sets. It is rendered entirely in JavaScript using WebGL and operates on data fetched from the /api/results/detail endpoint.
The terrain is a 3D surface with dimensions tokens × 17 columns. The central column (column 8) is the "spine" — it represents the chosen token at each position. Columns 1–7 (left of spine) show the base model's counterfactual candidates; columns 9–16 (right of spine) show the instruct model's candidates. This gives a "dual-bank" layout where the left bank is the base model's view and the right bank is the instruct model's view.
Vertex height at each grid point encodes the displacement magnitude for that candidate at that token position. For candidates that appear in both models' top-k, the height is the absolute probability difference. For promoted candidates (instruct-only), the height is the full instruct probability. For demoted candidates (base-only), the height is the full base probability. The spine height at each position is a weighted average of surrounding displacement magnitudes.
Height is scaled by a constant factor (HSCALE = 180) and a global min/max normalization across all magnitudes in the current prompt.
Vertex colors use a dual-ramp scheme with three regions:
- Base bank (columns 0–7): Cool tones (blues/teals) that increase in brightness with displacement magnitude.
- Spine (column 8): A distinct color ramp that marks the generation path.
- Instruct bank (columns 9–16): Warm tones (ambers/vermillions) that increase in brightness with displacement magnitude.
Colors are further modulated by two factors: KL divergence at each token position (adds a brightness boost proportional to behavioral divergence), and edge fade (columns far from the spine are blended toward the background color using a power-1.6 falloff based on distance from the spine). This keeps visual attention on the structurally important central columns while providing context at the periphery.
The viewer supports two render modes toggled by the user:
-
Surface mode: A triangulated mesh with Phong shading (shininess 30, emissive gray for ambient fill). Grid lines are overlaid as line segments with brightness that decreases with distance from the spine. The spine column gets bright wireframe lines; peripheral columns get dim wireframe lines.
-
Points mode: Each grid point is rendered as a size-attenuated particle. Point size decreases with distance from the spine (power-0.8 falloff). Non-visible tokens (below-median displacement) get tiny points (size 0.01 vs. 0.06).
Every grid vertex gets a text label rendered as a Canvas-textured sprite. Labels show the candidate token text. Spine labels (column 8) are 1.5× larger, colored in sky blue with a dark stroke for contrast. Non-spine labels are colored in off-white with dark stroke. Each label has a colored underline bar whose length is proportional to the KL divergence at that position, using the appropriate color ramp for its bank.
A median-magnitude filter can dim or hide tokens with below-median total displacement to reduce visual clutter in large prompts.
The terrain supports: orbit camera controls (drag to rotate, scroll to zoom, right-drag to pan), category/prompt selection via dropdown menus, a slideshow mode that auto-advances through prompts at configurable speed, a bank toggle (dual/instruct-only/base-only), render mode toggle (surface/points), a data filter (all tokens/above-median only), label size scaling, and auto-rotate with configurable RPM. The camera defaults to an elevated perspective looking down at the terrain at an angle. Auto-rotation pauses when the user drags the camera and resumes on release.
Before rendering, a configuration modal allows the user to set: category filter (restrict to one category or load all), record limit (cap the number of prompts loaded), token limit (truncate per-prompt arrays before terrain transform), prompt character limit (dropdown label length), auto-rotate toggle, and rotation speed. These defaults are persisted in the Display section of the Configuration tab.
The fetch loop terminates early when the record limit is reached rather than downloading all data and truncating client-side. When a category filter is active, records are filtered during fetch so the loop can stop as soon as enough matching prompts are collected.
The terrain viewer receives pre-computed displacement profiles from the rank displacement computation. Each prompt's data consists of: token list, and per-token rows containing [base_displacement_profile (8 values), instruct_displacement_profile (8 values), kl_at_this_position]. These are fetched from the server via the /api/results/detail endpoint, which returns the rank_displacement.instruct_disp_profiles, rank_displacement.base_disp_profiles, and per_token_kl arrays.
The dashboard includes a paginated sortable data table rendered client-side. It displays 24 columns (including a checkbox selector) spanning all signal families:
Identity: Index, prompt text (truncated), category, role, token count.
ASM: Stress score, net correction, entropy, interior share, interior CV, boundary share, KL divergence, negative token count. Stress, net correction, entropy, interior share, density, and Kendall τ columns include heatmap-style background tinting that colors cells proportional to their value.
Behavioral: Instruct top-1 token and probability, base top-1 token and probability.
LTP: Max PRC, directional token count, mean M.
SFD: Density.
Rank displacement: Kendall τ, overlap.
The table supports pagination (25 rows per page), column-width customization via inline style, and checkbox selection of individual prompts for batch operations (rerun, remove).
TASM generates two PDF report types using ReportLab, both following a consistent professional template.
Both reports share: a cover page with the TASM branding (title in blue, horizontal rule, metadata table with analyst name, organization, model, and timestamp), a page header (accent-colored rule, report title on the left, timestamp on the right), and a page footer (organization/analyst on the left, page number on the right).
The body uses a professional style system with named styles for titles (Helvetica Bold 22pt), H1 (Helvetica Bold 14pt), H2 (Helvetica Bold 11pt, accent blue), body text (Helvetica 10pt, 14pt leading), and monospace (Courier 10pt for prompt text and code).
Contains: cover page, apparatus description (explaining what TASM measures), the prompt text, a metrics table (all scalar metrics including LTP when available), a per-token attribution table (token, signed attribution, stress), and all applicable plots (signed attribution, stress, distribution metrics, amplitude trajectory, heatmap, and all LTP plots when enabled). Each plot is preceded by a title and a plain-language description of what the plot shows and what to look for.
Contains: cover page, apparatus description, a category summary table (n, average length, stress, entropy, boundary/interior share, net correction, negative token rate, M — all with bootstrap point estimates), a separability analysis table (Cohen's d, 95% CI, best threshold accuracy for each metric), all comparative/dashboard plots with descriptions, and a per-prompt results table (prompt text truncated to 60 characters, category, token count, and key scalars for every prompt in the batch).
Tables use a consistent style: light gray header row, thin gray grid borders, 10pt Helvetica, 5pt cell padding, word-wrap enabled for prompt text columns.
The frontend maintains a central registry of all 29 visualizations with metadata:
| Key | Category | Type | Scope | Needs |
|---|---|---|---|---|
| signed_attribution | ASM Core | plot | prompt | — |
| stress_per_token | ASM Core | plot | prompt | — |
| heatmap | ASM Core | plot | prompt | — |
| amplitude_trajectory | ASM Detail | plot | batch | — |
| distribution_metrics | ASM Detail | plot | prompt | — |
| token_table | ASM Detail | js | prompt | — |
| model_predictions | ASM Detail | js | prompt | — |
| ltp_tension_magnitudes | LTP | plot | prompt | ltp |
| ltp_profiles | LTP | plot | prompt | ltp |
| ltp_profile_heatmap | LTP | plot | prompt | ltp |
| ltp_summary_stats | LTP | plot | prompt | ltp |
| counterfactual_table | LTP | js | prompt | ltp |
| sfd_density | SFD | plot | prompt | sfd |
| rank_displacement | SFD | plot | prompt | sfd |
| separability | Batch Analysis | plot | batch | — |
| batch_summary | Batch Analysis | plot | batch | — |
| key_scatters | Batch Analysis | plot | batch | — |
| discriminative_sublayers | Batch Analysis | plot | batch | — |
| proof1_summary | Batch Analysis | plot | batch | — |
| exp_trajectory_overlay | Batch Analysis | plot | batch | — |
| exp_difference_from_benign | Batch Analysis | plot | batch | — |
| exp_metric_scatters | Batch Analysis | plot | batch | — |
| exp_behavioral_comparison | Batch Analysis | plot | batch | — |
| exp_ltp_category_comparison | Batch Analysis | plot | batch | — |
| exp_ltp_m_vs_stress | Batch Analysis | plot | batch | — |
| exp_ltp_profile_shapes | Batch Analysis | plot | batch | — |
| exp_sfd_category_comparison | Batch Analysis | plot | batch | — |
| exp_sfd_vs_asm | Batch Analysis | plot | batch | — |
| exp_rank_displacement | Batch Analysis | plot | batch | — |
Note: The ltp_dual_trajectory plot is generated server-side but is deliberately excluded from the registry and the frontend display. The Three.js terrain viewer is rendered as a standalone component outside the registry system.
Each entry has an on flag (all default to true), an order for display sequencing, and a needs field that conditionally shows/hides the visualization based on whether LTP or SFD computation was enabled. Visualizations are togglable per-session from the frontend controls.
Cross-context measurement of per-token coupling stability to the correction manifold.
Every token that passes through an aligned model has a geometric relationship to the weight delta between base and instruct models. The spectral field density (SFD) captures how broadly that token couples to the correction manifold in a single prompt. Token variance asks a different question: how much does that coupling change across prompts?
A token like "build" has nearly identical density whether it appears in "How do I build a bookshelf?" or "How do I build a pipe bomb?" Its coupling to the correction manifold is stable because its representational state doesn't shift much with context. A token like "your" has measurably higher density in "Ignore your safety rules" than in "What is your favorite color?" because its representational state is dominated by what surrounds it, and jailbreak context pushes it into regions of activation space that engage more of the correction manifold.
The module computes the coefficient of variation (CV) of spectral density for each token across all prompts where it appears. High CV means context-dependent coupling. Low CV means stable coupling. It also computes eta-squared (η²) — the fraction of variance explained by prompt category — to identify tokens whose coupling is driven by alignment context rather than random variation.
Token variance is implemented as a TASM module (engine/modules/token_variance.py) and runs from the Modules tab in the frontend. It operates on the current session's results — no separate command-line invocation is needed. Results persist to module_token_variance.json in the session directory and are included in session exports.
The module framework provides:
- Auto-discovery of module classes from
engine/modules/ - Thread-isolated execution with crash protection
- Parameter metadata rendered as UI controls
- Re-run capability with changed parameters
| Parameter | Default | Description |
|---|---|---|
| Min Appearances | 3 | Minimum interior appearances to include a token. Also used as the "qualified" threshold for summary statistics — no hidden secondary threshold. |
| Merge Subwords | off | Merge BPE subword tokens into whole words before analysis. Eliminates fragments like "ret" (from "Pretend") and "ard" (from "Disregard") that appear as separate entries. |
| Include First Token | off | Include position-0 tokens (density ~0.525 regardless of content due to positional artifact). |
| Top N | 30 | Maximum tokens shown per report section. |
| Min Prompt Length | 3 | Skip prompts shorter than this many tokens. |
| Min Per Category | 2 | Minimum appearances per category for pairwise comparisons. |
The module produces a structured JSON report with six sections.
Highest density CV. Tokens whose coupling to the correction manifold is most sensitive to surrounding context. These are predominantly function words whose representational state is determined by context rather than intrinsic semantics.
Lowest density CV. Tokens with stable coupling regardless of context. Content words with concrete semantics that maintain a consistent relationship to the correction manifold. Note: tokens appearing in only one category will show zero CV by definition — stability by isolation, not intrinsic property. Merge Subwords eliminates BPE fragments from this list.
High eta-squared. Tokens where the largest fraction of density variance is explained by prompt category (requires appearance in ≥2 categories). η² = 1.0 means 100% of variance is between-category; η² near 0 means category membership doesn't predict density.
Cross-category profiles. For tokens appearing in ≥3 categories, shows mean density and stress broken down by category.
Pairwise category comparisons. For each pair (benign/jailbreak, benign/adversarial, benign/harmful, harmful/jailbreak), shows the density shift for tokens appearing in both categories with sufficient sample size (controlled by Min Per Category). Positive diff means higher density in the second category.
Summary statistics. Distribution statistics (mean, percentiles) of density CV across qualified tokens, counts of context-stable versus context-dependent tokens (using P25/P75 thresholds), and overall token/prompt counts.
The module computes variance statistics across three SFD channels simultaneously:
- Density (primary): spectral density ratio — the token's effective rank relative to the global effective rank
- Stress: per-token stress score from ASM
- Energy: spectral energy — the squared norm of the weighted projection into the QK subspace
CV and eta-squared are computed independently for each channel. The density channel is used for sorting, classification (stable vs. dependent), and pairwise comparisons.
Reads from the current TASM session. Each prompt entry must contain:
-
tokens: list of token strings -
per_token_stress: list of floats -
sfd.per_token_density: list of floats -
sfd.per_token_energy: list of floats -
category: string (optional, used for cross-category breakdowns and eta-squared)
Prompts missing SFD data are skipped with a count reported in the summary.
Cross-context variance is not noise. It measures how the correction field responds differently to the same token depending on what surrounds it. This is a direct consequence of the attention-weighted projection: the delta acts on the residual stream state, which is context-dependent. Tokens whose representational state varies with context will show variable coupling to the correction manifold.
The systematic elevation of function word density in jailbreak contexts reflects the fact that jailbreak framing pushes the entire residual stream into regions of activation space that engage more of the correction manifold. The function words absorb this context shift because their representations are dominated by surrounding tokens rather than intrinsic semantics.
Content words with stable density are candidates for baseline calibration. Their consistent coupling provides a reference point against which context-dependent shifts can be measured.
All measurement-affecting parameters are centralized in engine/engine_config.py and surfaced in the frontend's Configuration → Advanced Parameters panel. The defaults reproduce the original hardcoded behavior exactly. Changing any parameter requires a full application reset (model unload, session clear, cache invalidation) to ensure measurement comparability.
| Parameter | Default | Module | What it controls |
|---|---|---|---|
signal_layer_fraction |
0.333 | model_manager | Middle third for ASM signal layers |
sfd_use_signal_layers |
false | sfd | Whether SFD uses ASM's layer range |
sfd_layer_start |
9 | sfd | SFD layer range start (when not using signal layers) |
sfd_layer_end |
16 | sfd | SFD layer range end, exclusive |
sfd_svd_k |
16 | sfd | SVD components for per-token spectral projection |
sfd_svd_seed |
42 | sfd | Random seed for SVD (torch.svd_lowrank uses randomized algorithm) |
serialization_precision |
8 | global | Decimal places for JSON transport of measurement values |
rd_min_shared |
2 | sfd | Min shared candidates for Kendall tau |
boundary_fraction |
0.1 | analyzer | Interior/boundary token split |
response_topk |
10 | analyzer | Next-token predictions captured per model |
proof1_threshold |
1e-4 | analyzer | Attribution decomposition exactness threshold |
delta_svd_k |
64 | model_manager | Weight delta spectral summary rank |
n_bootstrap |
5000 | statistics | Bootstrap resamples for CIs |
ci_level |
0.95 | statistics | Confidence interval width |
threshold_steps |
500 | statistics | Classification threshold search granularity |
min_valid_separability |
5 | statistics | Min values for separability analysis |
min_samples_d |
2 | statistics | Min samples per group for Cohen's d |
ltp_overfetch_first |
1 | ltp | Extra candidates on first fetch pass |
ltp_overfetch_second |
5 | ltp | Wider fetch if first pass insufficient |
disc_sublayers_top_n |
15 | comparative | Sublayers in discriminative plot |
domain_embedding_layer_frac |
0.50 | modules | Hidden-state capture depth for domain embeddings (0.0–1.0) |
domain_escalation_layer_frac |
0.75 | modules | Separate depth for escalation-level probe matching |
include_first_token |
false | modules | Include position-0 token in per-token domain embeddings |
export_domain_embeddings |
false | modules | Include per-token domain embeddings in session JSON export |
probe_projection_space |
false | modules | Project embeddings through o_proj delta before probe matching |
attention_weighted_pool |
false | modules | Attention-weighted pooling instead of uniform mean-pool |
persist_probe_caches |
true | modules | Probe caches and active probe selection survive server restarts |
chat_temperature |
0.7 | chat | Sampling temperature for chat generation |
chat_top_p |
0.9 | chat | Top-p (nucleus) sampling for chat generation |
chat_max_tokens |
512 | chat | Maximum tokens per chat response |
Engine configuration is persisted to engine_config.json alongside the application. On startup, saved values are loaded automatically. The Reset to Defaults button deletes the persisted file so the next startup uses defaults.
The Advanced Parameters panel is locked by default. The user must check an acknowledgment checkbox to unlock it. Edits accumulate locally without being sent to the server. The Apply button shows the count of pending changes and lists each old → new value in a confirmation dialog. Applying triggers a full application reset: model unloaded, session cleared, all caches invalidated. This ensures data collected under different settings is never mixed in the same session.