Written entirely by Claude, as a working record for agents more than for human readers: every number with its source file, and every claim since withdrawn. Some facts here may be out of date; where it disagrees with the post, trust the post. For the readable version, see the companion.

PCA, the scree curve and the two nulls

Eleven principal components of the adapter cloud sit above a structureless null and none sits above the permuted null; the elbow is unusable and four different variance spectra circulate for the same cloud.

currentverified 2026-09-16

Status: the secondary frame

Samuel's decision of 2026-09-08 - "we're going with the factor analysis so please redo the sphere using the biggest factors now and same for the other visualisations" - makes the five-factor oblimin solution the project's primary frame and the principal components the secondary one. See The factor chart for the convention that replaced the PC chart and Factor-first migration for what moved, element by element.

Nothing on this page is withdrawn. The components are still steered, still judged, still described on their own cards, and two arguments continue to need them:

One number on this page's subject changed with the migration. The blog page's right-hand scree panel used to plot the uncentred parallel analysis while the five factors on the same page come from the centred (ipsatised) matrix and results/fa_qwen35.json#n_factors.chosen is read off the centred one. The panel and the prose beside it now use #n_factors.parallel_analysis_centred. Retention at the reference N of 1,528 moves from 12 reduced / 9 unreduced (uncentred) to 9 reduced / 9 unreduced (centred), and the N-sensitivity sentence from 5 / 9 / 13 at N = 150 / 1,528 / 20,000 to 5 / 9 / 14. Recorded on Superseded claims.

What the scree figure shows

The blog page's left-hand scree panel plots the PCA spectrum of the adapter cloud against two trained nulls. It is fed by qwen35/analysis/scree_null_matched.json (qwen35/build_blog_page.py, scree_svg(), which reads that file by name); qwen35/analysis/scree_null.json is the earlier version and is superseded. Both arms in the current file were trained at the zoo's exact objective - see The null control arms.

First twelve components, per cent of variance, from qwen35/analysis/scree_null_matched.json:

rank real (#real) labels permuted (#permuted) preference destroyed (#shuffled)
1 13.362 13.575 1.233
2 11.207 10.811 1.199
3 5.789 5.058 1.188
4 3.866 3.817 1.163
5 2.932 2.821 1.152
6 2.237 2.073 1.150
7 1.709 1.775 1.141
8 1.543 1.564 1.132
9 1.275 1.289 1.126
10 1.223 1.181 1.121
11 1.146 1.124 1.116
12 1.114 1.075 1.111

(Values above are the first twelve of the twenty stored in each list, quoted to three decimals as they appear; n = 100.)

Counts stored in the same file:

What the two nulls mean

The blog page draws the conclusion the counts force: the scree tells you how much structure a training run produces and nothing about whether that structure lines up with the trait names. Everything connecting a direction to a word rests on steering and judging (Steering the base model along weight-space directions) or on the labelled tests in Polarity, bipolarity and the trait graph, never on the eigenvalues.

The elbow is explicitly declared unusable. The blog page: the largest single drop puts the elbow after the second component, maximum curvature says the third, and a chord from the first point to the tail says the first, because the leading two eigenvalues are nearly equal - "Three criteria, three answers". The page also records the correction: with only the elbow to go on, describing six components looked generous; against the structureless null it is conservative. That reversal is logged in Superseded geometry claims.

Four different variance spectra for the same cloud

These are all real, all cited below, and they are not interchangeable. Anyone copying a "first two components take X%" figure must say which one.

source what it is PC1 PC2
qwen35/results/fa_qwen35.json#pca_from_gram.centered_var_pct exact 134-trait double-centred Gram 12.4946 10.9847
qwen35/analysis/blog_data.json#viz.var (= analysis/alien.json#var_explained) 134 traits, sketch stage1_k32 12.669 11.252
qwen35/analysis/scree_null_matched.json#real 100 Goldberg markers 13.362 11.207
qwen35/analysis/geometry_stage1.json#explained_var_top10 100 markers, sketch, k=30 basis 13.40 11.22

The blog page's own map caption uses the 134-trait sketch figures: "The first two components take 12.7% and 11.3% of the variance ... 40% in eight dimensions" (qwen35/blog_page/index.html; the 40% is the sum of the first eight entries of analysis/alien.json#var_explained).

A fifth number exists for the raw (uncentred) 134x134 cosine matrix: qwen35/results/decomposition.json#spectrum.eigenvalue_share = 0.12523, 0.10113, 0.08096, 0.04342, ... with #spectrum.participation_ratio = 25.720397850313308 and #spectrum.top5_share = 0.3751747844019098. The participation ratio is the figure PHASE3_VERDICT keeps: "Participation ratio 25.7: five factors are a real but thin slice of a much higher-dimensional geometry."

The known trap: where the stored real curve came from

The maintainer recorded a reproduction check that could not reproduce the stored real curve from the expected Gram. .garden/journal/2026-09-05.md:

Scree null regenerated from the matched Grams; stored real came from gram_sketch100.npz, not gram_sweep (took a minute to find).

Evidence still visible in the files, recorded rather than resolved:

So the real curve on the current page is a 100-trait, sketch-derived spectrum, not the exact 134-trait one. Given the reported sketch fidelity (r = 0.9996, see Weight-space geometry of the 134-adapter zoo) the shape is not expected to change, but the provenance is what it is and nothing on disk shows the curve being regenerated from gram_sweep.npz. This is flagged in Superseded geometry claims and in the section report.

PC loadings and cosines with the named axes

qwen35/analysis/pc_loadings.json#pcs holds, for each of PC1-PC6, its cosine with each of the five named Big Five axes and the five traits loading highest at either end. The largest cosine per component:

component largest absolute cosine with a named axis value source key
PC1 Agreeableness +0.8224698544025675 #pcs.PC1.cos.Agreeableness
PC2 Extraversion +0.8136539390702753 #pcs.PC2.cos.Extraversion
PC3 Intellect -0.8515068460790329 #pcs.PC3.cos.Intellect
PC4 EmotionalStability -0.5090913382861884 #pcs.PC4.cos.EmotionalStability
PC5 EmotionalStability -0.433233611874007 #pcs.PC5.cos.EmotionalStability
PC6 Agreeableness +0.1360460889635613 #pcs.PC6.cos.Agreeableness

PC1 also carries -0.7001299478434748 on Conscientiousness, which is why the blog page calls it a blend rather than a factor. Per-component detail is on PC1 - Flooding and Composure .. PC6 - Feeling and Deliberation.

pc_loadings.json additionally carries a #seed block: same_trait_cos = 0.01658715905967511, same_trait_deg = 89.04958220635345, diff_trait_cos = 0.0013512710743004668, n = 40, rank1 = 40. Those are the original, objective-mismatched seed-paired numbers; the current figure is +0.01806 (see The seed floor). The blog page's prose quotes the matched 0.018 while this data file still holds 0.0166.

Dimension sweep and intrinsic coordinates

qwen35/analysis/geometry_k_sweep.json sweeps the PCA dimension k over 5, 10, 20, 30, 40, 50, 70, 99 with columns [k, whitened_axis_abscos, whitened_null, whitened_p, unwhitened_axis_abscos, unwhitened_null, unwhitened_p, loo_acc_whitened, loo_acc_unwhitened]. Its #reading:

Keying classification: read UNWHITENED (0.98 at every k). Orthogonality: read WHITENED (p<=0.01 for k=5..70). k=99 = n-1, whitening fully degenerate.

At k=5 the row is [5, 0.1106, 0.3487, 0.0033, 0.2297, 0.394, 0.01, 0.99, 0.98]. The sweep's #description records that the underlying geometry is "bilinear sketch k=32 (validated r=0.9996 vs exact)" over 100 Big Five trait adapters at LoRA seed 0, and its #null is "shuffled-keying within factor, 300 permutations".

qwen35/analysis/geometry_stage1.json carries the matched pair of readings at k=30 over n = 100:

qwen35/analysis/intrinsic_coords.json records a separate, smaller object over n_traits = 100: #eff_dim = 3.2694443860505626, #variance_shares = [0.4620546637786367, 0.2403440646151083, 0.14015058574881312, 0.11453762965028536, 0.04291305620715653], #test_retest = [0.786..., 0.872..., 0.899..., 0.833..., 0.859...], #ceiling_24prompts = 0.9926908730732167, #spearman_weight_judged = 0.5823269539942723, with #null_mean = -0.00043594766353703294 and #null_sd = 0.025062880236739825. No producing script for this file exists in the repo; the file's own keys are all the provenance there is, and the numbers are not used by the blog page.

Related: Weight-space geometry of the 134-adapter zoo, Factor analysis of the adapter Gram, The null control arms, Polarity, bipolarity and the trait graph, Superseded geometry claims, Glossary.