EigenTrace metrics: names, formulas, code, ranges, caveats

Reference page for every metric name that appears on air (script beats, ticker) or on the site (pages, docs/data/YYYYMMDD.json). Each row gives the standard name where one exists, the exact formula as implemented, the code location, the value range, and caveats that are either provable from the code or measured. Verified against the repository on 2026-09-10. Measured ranges come from the 99 most recent story segments with data (tmp/segments/*_segment.json, 2026-08-25 to 2026-09-10) unless stated otherwise.

Substrate common to everything below. Every vector is a BAAI/bge-large-en-v1.5 embedding (1024 dimensions, unit-normalized, computed on CPU by geometric_engine.GeometricPerturbationEngine.embed_texts). e_i is the embedding of model i’s whole response, N the number of models that returned text (4 or 5 in the sample), c = mean_i e_i the raw centroid, ĉ = c/‖c‖ the unit centroid, h the embedding of the headline, d the consensus density. “Vocab” means the 184,789-word tensor vocab/global_vocab.json unless stated otherwise. All embedding-side computations are deterministic; the claim extractor, Summary Plus rewrites and the two Wild Weasel segments call language models and are not.

Where numbers surface: air = beats built by script_v3.py and read by the player; ticker = segment_player.update_ticker; attribution = the attribution block of each segment file; log = audit_log.jsonl; site data = docs/data/YYYYMMDD.json written by data_exporter.py.

1. Panel geometry (how alike the responses are)

EigenTrace name Standard name Formula Code (file:function) Range Caveat
consensus_density, “density” Mean pairwise cosine similarity d = 2/(N(N-1)) · Σ_{i<j} e_i·e_j (upper triangle of the Gram matrix) geometric_engine.py:GeometricPerturbationEngine.compute_consensus_density, called from .run; stored by batch_producer.py:stage_4_generate_scripts (3 dp). Air: archive beat; attribution, log, site data (mean_density daily) Theoretical [-1, 1]; measured 0.864-0.950, median 0.916 Whole-response embeddings, so shared length and format count as agreement; a floor near 0.9 is normal for same-prompt summaries. Mean VIX and state_flag are functions of this number (rows below). Equivalent identity for unit vectors: ‖c‖² = (1 + (N-1)d)/N.
per-model VIX, “geometric VIX”, “friction”, model_vix Scaled cosine distance to the unit centroid (no standard scale) VIX_i = clip(500 · (1 - e_i·ĉ), 0, 100) batch_producer.py:stage_3_geometric (sets resp.eigen_vix). Air: script_v3.py beat_05_friction_map (“X at 22.7”, outlier = argmax, most aligned = argmin); attribution model_vix, log, site data [0, 100] by construction (100 is reached at cos = 0.8); measured per-story max 11.5-41.6 (median 22.7), min 5.7-21.2 Bounded by the clip, not by data. The per-model values are not independent: Σ_i (1 - e_i·ĉ) = N(1 - ‖c‖), so they sum to a function of density. The factor 500 is a display choice (source comment: “typical range is 0.01-0.15”). An outlier always exists (argmax). proxy_auditor.eigen_label bands (“Ideological Overwrite” at 85 etc.) and detect_callouts are not called by the producer.
mean VIX, mean_vix, ticker “Friction” 500·(1 - ‖c‖); determined by density mean_vix = (1/N) Σ_i VIX_i = 500 · (1 - sqrt((1 + (N-1)d)/N)), exact whenever no VIX_i hits the clip (proof: Σ_i e_i·ĉ = N‖c‖ and ‖c‖² = (1+(N-1)d)/N for unit vectors) batch_producer.py:stage_4_generate_scripts (attribution mean_vix, 2 dp); segment_player.py:update_ticker prints Friction: {mean_vix:.1f}; script_v3.py archive beat (“Mean VIX”) Measured 9.4-28.1, median 17.0 Carries no information beyond d and N. Checked: synthetic panels reproduce the identity to 1e-13; on the 99 stored segments the median gap between the identity and the stored value is 0.047 (rounding of stored inputs). Until 2026-09-09 the ticker read a top-level gap_vix key that never existed and printed “Friction: 0.0000” on every story (fixed in commit a606d537, 2026-09-10 in this tree). batch_producer.py:stage_7_write_segments also writes the ticker file, in a format without Friction.
state_flag: HIGH_FRICTION / CONTESTED / LOCKSTEP / NOMINAL Threshold on density (one bit, effectively) if mean_vix > 30: HIGH_FRICTION; elif mean_vix > 15: CONTESTED; elif density > 0.9: LOCKSTEP; else NOMINAL batch_producer.py:stage_4_generate_scripts (lines ~1360-1374). Air: ticker [STATE], Director prompt, archive beat; attribution, log, site data Four labels; measured on 99 stories: CONTESTED 66, LOCKSTEP 33, HIGH_FRICTION 0, NOMINAL 0 Because mean VIX is a function of d, the flag is a density threshold. For N = 5: HIGH_FRICTION iff d < 0.8545; CONTESTED iff 0.8545 ≤ d < 0.9261; LOCKSTEP iff d ≥ 0.9261 (the > 0.9 test is then automatic). For N = 4 the cut points are 0.8448 and 0.9212. NOMINAL requires d ≤ 0.9 and d ≥ 0.9261 at once, so it is unreachable for N ≥ 3 (reachable only for N = 2, 0.8818 ≤ d ≤ 0.9). HIGH_FRICTION needs d < 0.8545; the minimum density in the sample is 0.864.
callouts: HIGH_FRICTION / UNUSUALLY_ALIGNED (per model) Ratio to the panel mean HIGH_FRICTION if mean_vix > 2 and VIX_i > 2·mean_vix; UNUSUALLY_ALIGNED if mean_vix > 5 and VIX_i < 0.4·mean_vix batch_producer.py:stage_3_geometric (r["callouts"]) Labels Logged only. Read into a variable in stage 4 and not used; not in attribution, log, or site data. dashboard.html expects callouts in audit_log.jsonl, which has never contained them (0 of 2,204 records).
vix_spread (EigenChing axis 6) Range of per-model VIX max_i VIX_i - min_i VIX_i script_v3.py beat_18b_state_vector; batch_producer.py:stage_summary_plus_probe [0, 100]; measured 1.8-29.0, median 11.1 Introduced as axis 6 on 2026-09-09 (before that, axis 6 was mean VIX, which duplicates axis 1). Shares the 500× scale and the clip of per-model VIX.
spectral_gap, smallest_eigenvalue (λ_min) Eigenvalues of the response covariance λ_max / Σ(other λ); min λ of np.cov(e_i - c) geometric_engine.py:GeometricPerturbationEngine.run (EigentraceResult) λ_min ≡ 0 Not aired, not stored. With N ≤ 5 rows in 1024 dimensions the covariance has rank ≤ N-1, so λ_min is 0 up to float error and spectral_gap is a ratio over at most N-1 nonzero eigenvalues.

2. Absent-word channels (“void”)

EigenTrace name Standard name Formula Code (file:function) Range Caveat
void words (aired), void_words, synthesis_words, ticker “Core Factors” Headline-nearest vocabulary absent from all responses (no standard equivalent) Take the top 200 vocab words by cos(h, w); drop words shorter than 4 characters; keep words whose lowercase whole-word regex does not match the concatenated responses; top 5 by cos(h, w). Stage 4 then removes words equal to a headline word (≥ 3 chars) or sharing their first 4 characters with a headline word (≥ 4 chars; no stemming), keeps 15 (if nothing survives, the unfiltered list is kept); synthesis_words = void_words[:5]; the beats read the top 5 batch_producer.py:_compute_void (r["void_override"]); filter in batch_producer.py:stage_4_generate_scripts; ticker segment_player.py:update_ticker. Air: void beats (absorbed by the ensemble when it runs), Director prompt; attribution, log, site data (top_void_words daily) 0-5 words; measured 1-5, median 4 Anchored on the headline, not the source body. “Absent” is a surface-form check: an inflection the models did write (e.g. “sanctions” for “sanction”) still counts as absent. The list is the same kind of object as the logos words (headline-nearest vocabulary with a not-said filter), which is why they often overlap. void_context and void_frequency.json are computed on a different list (next row), so their HIGH_SALIENCE / GENERIC_ARTIFACT labels do not describe the aired words. If _compute_void fails, the donut list below is aired instead.
donut void, geo.void_concepts, “in-domain void”, “annular retrieval” Two-threshold selection on cosine similarities Keep vocab words with cos(h, w) > 0.52 (outer ring) and cos(ĉ, w) < inner (inner hole), inner = min(0.60 + max(0, (g - 0.80)·0.20), 0.78) where g is the mean of the full N × N Gram matrix including its diagonal, i.e. g = (1 + (N-1)d)/N = ‖c‖², not d; sort ascending by cos(ĉ, w); skip words among the 5 vocab words nearest h and words with Zipf frequency below 2.8; if fewer than k words, raise inner by 0.03 up to four times (capped at the initial inner + 0.10, at most 0.82), then lower the outer ring by 0.03 up to four times; hard fallback ranks by cos(h, w) - cos(ĉ, w) latent_retrieval.py:VocabTensor.in_domain_void, called by geometric_engine.py:GeometricPerturbationEngine.run Up to k = 5 words Not the aired list unless the aired computation fails. Feeds void_context, void_frequency.json, reconstruction_alignment (its centroid), and the Wild Weasel fallback; the ensemble channel donut would recompute it with k = 10 but never runs in production (ensemble row). The docstring says the adaptive multiplier is 0.5 and the base 0.65; the code uses 0.20 and 0.60.
source_void: absent_words, absent_count, absent_ratio, absent_phrases Set difference of source vocabulary and response vocabulary Source S = title + “. “ + RSS summary + body[:1500]. Source words = lowercase alphabetic tokens ≥ 4 chars not in a 70-word stoplist. absent_words = source words whose surface form and Porter stem appear in no response, excluding headline derivatives (same Porter stem as a headline word ≥ 4 chars, or one a substring of the other, both ≥ 4 chars; the intended shared-prefix test compares only the full shorter word and so adds nothing) and, from 2026-09-19, excluding a word whose British/American counterpart spelling a response used (six rule families — -ise/-ize, -our/-or, -re/-er, -ll-/-l-, -ce/-se, -ogue/-og — with an exception list for words spelled -ise in every variety and an ambiguous list held back; spelling_variants.py; the rescued pairs are stored in spelling_variant_kept and the pre-2026-09-19 figures in absent_count_v1 / absent_ratio_v1). absent_ratio = absent_count / source_word_count. absent_phrases = source bigrams (two non-stop tokens ≥ 3 chars) and trigrams (≥ 2 non-stop tokens, ≥ 8 chars) not present as substrings in any lowercased response, first 20 in alphabetical order eigentrace_math.py:source_anchored_void; batch_producer.py:stage_3_geometric. Air: lexical-void beat; consequence raycast input; EigenChing axis 2; attribution, site data absent_ratio in [0, 1]; measured 0-0.505, median 0.216, exactly 0 in 7% The only void channel that reads the source body, and it reads at most 1,500 characters of it (compression reads 1,000, the spiral up to 5,000 of title + summary + body). Both the count and the ratio depend on where the 1,500-character cut falls. The phrase list is alphabetical, not ranked.
void_context labels: HIGH_SALIENCE, POSSIBLE_SIGNAL, GENERIC_ARTIFACT, EMBEDDING_SIGNAL Document frequency of a void word across past stories For each donut word: in_source = substring of S; global_pct = 100 × (stories whose donut list contained the word) / total stories (also per category). HIGH_SALIENCE if in source and global_pct < 10; POSSIBLE_SIGNAL if in source and < 30; GENERIC_ARTIFACT if global_pct ≥ 30; EMBEDDING_SIGNAL if not in source and < 10; else POSSIBLE_SIGNAL eigentrace_math.py:score_void_context, update_void_frequency (file void_frequency.json, total_stories = 10,753 on 2026-09-10; it increments once per story) Percentages [0, 100]; one label per word Scored on the donut list, not on the aired void words. Counts accumulate over the whole history without decay, so a word’s percentage reflects when it entered the vocabulary as much as its current rate. in_source is a substring test (“iran” inside “iranian”).
void ensemble top5, “surfaced by k channels” Vote across candidate lists Candidates from whichever of nine registered lists are present on the result dict (headline_void, source_void, logos_v10, sp_flat, sp_spiral, sp_void, synthesis, plus donut and vf_idf computed fresh); drop junk, headline-stem and said-stem words; weight 1/(1 + rank) (0.3 for source-void words); merge by stem key (weights add) and by geographic group (survivor gains 0.25 × the loser’s weight); rank by (number of channels, summed weight); top 5. Raycast arms (consequence_engine.raycast_void_words, depths 1.5/2.0/3.0) per word; Mistral “opine”; archive RAG void_ensemble.py:vote, harvest_channels, run_story_ensemble, build_ensemble_beats, weave_beats; called from batch_producer.py:stage_3_geometric with eng=None, vt=None. Air: ensemble_intro, ensemble_top5, ensemble_raycast, ensemble_opine, ensemble_memory; attribution ensemble 5 words (96 of 99); measured vote counts 1-3 (2 votes for 420 of 491 words) In production only four channels vote: logos_v10, sp_flat, sp_spiral, sp_void (channels_run in 99 of 99 recent segments). headline_void and synthesis read keys (void_words, synthesis_words) that stage 4 creates after the ensemble has run, source_void is assigned to the dict one line after the call, and donut/vf_idf require an engine and vocab tensor the producer passes as None. Of the four, sp_flat is the logos list stem-deduplicated (declared downstream_of logos_v10 in REGISTRY), so every logos word casts two votes by construction, and sp_void is the headline void (void_override) re-labelled. The ensemble ran on 99 of 99 recent stories and removed beats 06, 07, 09 and the two consequence beats each time (absorbs).

3. Logos and the anti-consensus direction

EigenTrace name Standard name Formula Code (file:function) Range Caveat
logos_words, “Logos synthesis”, “the anti-consensus point”, sp_channels.flat, “flat raycast” Projected gradient descent on the unit sphere with a linear objective; readout = nearest vocabulary Minimize L(x) = mean_i (1 - cos(x, e_i)) + 0.75·cos(x, ĉ) - 0.30·cos(x, h) with AdamW (lr 0.05, weight decay 1e-4), 150 steps, start x₀ = ĉ, renormalize x to unit length after every step. Words: the 25 vocab words nearest x*; keep those whose every token’s Porter stem was not written by any model; take 5; if fewer than 3 survive, use the unfiltered top 5 geometric_engine.py:reconstruct_unaligned_truth_v10 (adopted 2026-07-06); readout in batch_producer.py:stage_3_geometric; fallback reconstruct_unaligned_truth (V9: LogosLossV9 + 0.15·cos(x, ĉ) - 0.30·cos(x, h)). Air: beat_08_logos_reveal; Summary Plus prompt line “Flat raycast (SVD anti-consensus direction)”; attribution, log, site data (top_logos_words) Always 5 words (99 of 99) Provable: for unit e_i, mean_i(1 - cos(x, e_i)) = 1 - ‖c‖·cos(x, ĉ), so L(x) = 1 + (0.75 - ‖c‖)·cos(x, ĉ) - 0.30·cos(x, h), which is linear in x and minimized on the sphere at x* ∝ (‖c‖ - 0.75)·ĉ + 0.30·h. Since ‖c‖ = sqrt((1 + (N-1)d)/N) exceeds 0.75 whenever d > 0.453 (N = 5), the net pull is toward the centroid at every density seen in production. Measured: on synthetic panels cos(x*, closed form) = 0.9999; at d = 0.948, cos(x*, ĉ) = 0.967 and cos(x*, h) = 0.981. The words therefore differ from the “top concepts” only because of the said-stem filter, and the silent unfiltered fallback removes even that. No SVD and no ray are involved despite the “flat raycast” label; the on-air explainer’s “start at a random spot” is wrong (start is the centroid, deterministic). docs/vf-idf.html prints the same formula and states that the +0.75 cos(x, c) term repels the consensus; that is true of the term alone, not of the sum.
residual, void_vector (“Layer 8”, “Channel 4”) Difference vector source minus centroid v = e_source - c, source = title + “. “ + summary + body[:1500]; stored magnitude = ‖v‖ and the 5 coordinate indices with the largest absolute value eigentrace_math.py:compute_void_vector; batch_producer.py:stage_3_geometric (attribution void_vector) ‖v‖ in [0, 2]; measured 0.331-0.602, median 0.441 Not aired and not projected to words in production (the vocabulary arguments are not passed). top_void_dims are raw coordinate indices of the embedding space and mean nothing individually. This is the only quantity in the code that points from the consensus toward the source; the logos vector above does not. An off-repository test on 2026-09-09 (300 stories) found this residual aligns with dropped words and killshot claims more than with kept words; that script is not in this repository, so treat the result as unpublished.

4. SVD and “spectral” quantities

EigenTrace name Standard name Formula Code (file:function) Range Caveat
null_space_vec, “SVD null space”, “Channel 3”, null_space_claims, null_alignment Right singular vector with the smallest singular value; claim ranking by absolute cosine Y = N × 1024 matrix of unit rows; economy SVD Y = UΣVᵀ; v = V[-1]. Claims (section 5) ranked by abs(cos(v, e_claim)); top 3 kept with the signed cosine as null_alignment geometric_engine.py:calculate_svd_reconstruction (null_space_vec); ranking in batch_producer.py:stage_3_geometric. Air: Director prompt (“Null claim”), triple-confirmation check, script_v3.py null-space beats; attribution (top 2), log (top 3) null_alignment in [-1, 1]; 2 claims stored in 99% of segments v lies in the row space of the responses (economy SVD), so it is a combination of what the models wrote, not a direction outside it; its sign is arbitrary, which is why ranking uses the absolute value. Until 2026-09-09 the SVD was taken of the mean-centred matrix, whose rank is at most N-1, so its last right singular vector was an arbitrary vector of the null space and changed with row order (the “flat raycast” words derived from it were noise; see the code comment dated 2026-09-09). docs/index.md calls this “SVD null-space projection”.
consensus_compression, null_space_energy, reconstruction_alignment (“semantic tomography”) Normalized singular values of the centred matrix; cosine to the donut centroid On Y_c = Y - mean row: S[0] / ΣS; S[-1] / S[0]; cos(v, void_centroid) geometric_engine.py:calculate_svd_reconstruction; consensus_compression and reconstruction_alignment are read into unused variables in batch_producer.py:stage_4_generate_scripts, null_space_energy is not read at all compression in [1/(N-1), 1]; null_space_energy ≡ 0; alignment in [-1, 1] Not aired, not in attribution, log, or site data as of 2026-09-10 (printed only by proxy_auditor.py’s own audit loop and the offline tools eigentrace_agi.py and eigentrace_demo.py, none of which the producer runs). null_space_energy is identically zero: a centred matrix with N rows has rank ≤ N-1, so its N-th singular value is 0 up to float error.
spectral resonance, interference, spectral_entropy (“Logos Transform”) Real FFT over the coordinate index of each embedding X_i = rfft(e_i) over the 1024 coordinates (513 bins). resonance = mean_i abs(X_i[0]) = mean_i abs(Σ_j e_ij); interference = mean over models and bins 1-512 of abs(X_i[k]); spectral_entropy = mean over models of the Shannon entropy of the normalized power spectrum geometric_engine.py:calculate_spectral_resonance; batch_producer.py:stage_3_geometric (r["spectral"]); dashboard_server.py reads spectral_resonance from audit_log.jsonl resonance in [0, 32]; entropy in [0, ln 513 ≈ 6.24] Not a spectrum in the signal-processing sense: embedding coordinates have no order. Any permutation of the 1024 coordinates leaves every cosine in this document unchanged but changes interference and spectral_entropy; the “DC” bin is just the projection of e_i on the all-ones vector. Not aired and not on the site; audit_log.jsonl has never carried the key the dashboard reads (0 of 2,204 records), and no dashboard_server process was running on 2026-09-10.
“spiral”, sp_channels.spiral, “convergence spiral” Sentence-centroid nearest vocabulary with a sentence-convergence count Split S (title + summary + body, ≤ 5,000 chars) into sentences longer than 15 characters (need ≥ 3); embed them; cen = unit mean of sentence embeddings; pool = top 400 of the 50,515-word clean vocabulary (vocab/global_vocab_clean) by cos(w, cen). For each pool word (≥ 4 chars, not in HARD_DROP): conv = number of sentences with cos(w, s) > 0.45, require ≥ 2; drop words present (whole word) in the joined summaries; keep words not present in S and with idf ≥ median idf; sort by (-conv, 1 - max_s cos(w, s)); drop phrase-aware named entities; top 8, cut to 6 by the producer, then stem-deduplicated to 5 spiral_sampler.py:convergence_spiral; wired in batch_producer.py:stage_3_geometric (sp_channels, since 2026-07-03; first called 2026-06-25). Air: Summary Plus intro (“from the convergence spiral”); attribution sp_channels 0-5 words; measured median 5, empty in 9% Contains no SVD, although the Summary Plus prompt and the generate_summary_plus docstring call it an “independent second SVD derivation”. The idf filter is inert: spiral_sampler reads void_frequency.json as a flat word-to-count dictionary, but the file nests words under "global", so every word gets count 1, the same idf ln((total_stories + 1)/2) (total_stories is the file’s only numeric top-level value), and the ≥ median test passes everything. Words must be absent from the source, so the list is vocabulary near the source’s sentence centroid that neither the source nor the summaries used. Importing spiral_sampler loads the confront10 / confront_keeper_v3 research modules and a 207 MB vocabulary tensor, and calls os.chdir to the repository root as a side effect. The “spiral leg” described in docs/vf-idf.html (T = normalize(h + 2.0·d̂) per void word) is a different computation belonging to that page’s instrument.

5. Claims and killshots

EigenTrace name Standard name Formula Code (file:function) Range Caveat
atomic claims LLM extraction Mistral (mistral:latest via Ollama, temperature 0, ≤ 500 tokens) extracts “atomic factual claims” from headline + RSS summary as a JSON array; fallbacks parse quoted strings or lines; claims shorter than 11 characters dropped claim_extractor.py:extract_claims 0-10+ claims The input is the headline and the RSS blurb, never the article body. Not deterministic (model output), though temperature is 0.
salience Cosine to the headline salience = cos(e_claim, h) claim_extractor.py:score_claim_coverage [-1, 1] in principle; in practice well above 0 Compares a claim with the text it was cut from, so salience is high by construction; the 0.45 gate below rarely binds.
coverage, covered_by, partial, omitted_by, coverage_ratio Cosine between claim and each whole response sim_m = cos(e_claim, e_m); covered if sim_m ≥ 0.75; partial if 0.65 ≤ sim_m < 0.75; otherwise omitted; coverage_ratio = covered / N claim_extractor.py:score_claim_coverage (COVERAGE_THRESHOLD = 0.75) coverage_ratio in {0, 1/N, …, 1} One cosine between a one-sentence claim and a multi-sentence response: a claim paraphrased inside a long response can score “omitted”, and a response that only discusses the same topic can score “covered”.
killshots, claim_killshots Filter on the above salience ≥ 0.45 and coverage_ratio ≤ 0.2 and omitted_by non-empty; sorted by salience; top 3 stored and aired claim_extractor.py:find_killshots; batch_producer.py:stage_3_geometric. Air: beat_15_killshots (only claims with a named omitter); attribution, log, site data 0-3 per story; measured median 2, none in 10% With N = 5, coverage_ratio ≤ 0.2 allows one model to cover the claim while the other four are merely “partial”, which left omitted_by empty; 94 of the 215 killshots stored in the sample (44%, all before the fix) have no omitter. The omitted_by requirement was added 2026-09-09; in the 12 segments since 2026-09-09 22:00, 0 of 15 stored killshots have an empty omitted_by.
dual / triple confirmation Set intersection of word lists dual = set(void_words[:10]) ∩ set(logos_words[:10]) (exact lowercase strings); triple = dual ∩ {void words that occur as substrings of the top-2 null-space claims} script_v3.py beat_09_confirmation (its own computation from the attribution) and data_exporter.py (dual_confirmed, triple_confirmed), both on the top 10; batch_producer.py:stage_4_generate_scripts computes a top-5 version that nothing reads 0-5 words (logos_words never exceeds 5) Both lists are headline-nearest vocabulary with a not-said filter (sections 2 and 3), so overlap measures shared construction, not agreement between independent methods, although the beat says “three algorithms, three search spaces”.

6. Language compression (Layers 13-15)

Source text for this group is title + “. “ + RSS summary + body[:1000] (note: source_void uses body[:1500]). Code: eigentrace_math.py:score_language_compression, called from batch_producer.py:stage_3_geometric; aired in script_v3.py beat_11_compression_report (“Verb drift … Entity retention … Attribution buffers inserted … Overall compression score”); stored in attribution compression and site data.

EigenTrace name Standard name Formula Code (file:function) Range Caveat
verb_downgrade, “verb drift” Zipf word-frequency shift of content verbs Content verbs = NLTK POS tags starting with VB, longer than 2 chars, not in a 32-word auxiliary list. drift = meanZipf(response verbs) - meanZipf(source verbs) (wordfreq, English); per model vd = clip(drift / 2, 0, 1); reported value = mean over models eigentrace_math.py:_extract_content_verbs, _mean_zipf, score_language_compression; EigenChing axis 3 [0, 1]; measured exactly 0 in 65%, p90 0.087, max 0.767 One-sided: models using rarer verbs than the source give 0, not a negative value. If POS tagging fails the verb lists are empty and drift is 0. The /2 scale is a choice (drift of +2 Zipf units = 1.0).
entity_retention, entity_abstraction_rate Fraction of source “entities” present in the response Source entities (rule v2, from 2026-09-19) = regex runs of capitalized words [A-Z][a-z]+( [A-Z][a-z]+)* plus all-caps tokens, minus 24 sentence starters, minus scraper chrome and runs spanning a line break, with leading auxiliaries and trailing verbs trimmed off headline fragments (“Trump Says” → “Trump”) and one-token runs dropped when every appearance starts a sentence and the source itself also writes the word in lower case. Retained if any registered surface form — the full run, the family/last-token key (particles stripped both sides, generational suffixes dropped, family-first names keyed on the family token from a registered map so “Xi Jinping” keys Xi) or a registered press alias — occurs as a case-sensitive whole word in the response; per model retained / total; mean over models; entity_abstraction_rate = 1 - mean. Rule v1 (before 2026-09-19): the unfiltered run list, retained if the whole run is a case-insensitive substring of the response. Both are computed on every call and both are stored (entity_retention_v1, entity_retention_v2, entity_retention_rule); entity_rule="v1" or EIGENTRACE_ENTITY_RULE=v1 reproduces the old number eigentrace_math.py:score_language_compression, name_key.py; EigenChing axis 4 [0, 1]; on 1,524 five-model body_visible stories: v2 median 0.562 (5th-95th percentile 0.280-0.844, mean 0.565), v1 on the same stories median 0.556 (0.333-0.780, mean 0.558). Values stored before 2026-09-19 are v1 Still not NER. The audit that forced the change (analysis/experiments_v1/entity_retention_audit/) measured v1 on that cell: 15.3% of the pairs it scored retained were substring hits inside another word (“US” in “stimulus”, “Israel” in “Israeli”), 23.1% of the person pairs it scored missing were present because the greedy run swallows the title, and only 13.07% of the list was a person at all. v2 removes those three failures and nothing else: it does not add a tagger, so an unregistered family-first name is still keyed on its last token, and a place or organisation is still keyed on its last token, which is not always its name.
attribution_buffer, hedge count, “hedges” Count of hedge words added by the model Three fixed lists (epistemic 11 words, attribution 10, distancing 9). Per model: distinct response words in each list that are not in the source; hedge_count = sum of the three; total = sum over models; avg_per_model = total / N eigentrace_math.py:HEDGE_EPISTEMIC etc., score_language_compression; EigenChing axis 5; Director calibration text (“if hedges are above 200”) ≥ 0; measured total 1-25, median 8 Word sets per response, so a hedge repeated ten times counts once per model. “alleged” and “claimed” appear in both the attribution and distancing lists and count twice; “so-called” can never match because tokens are \w+ runs, so the distancing list has 8 effective entries. The overview page’s “Hedges / reflection 0.54” is a different quantity (the self-audit’s eigentrace/core.py:_hedge_density on the broadcast’s own narration).
compression_score Weighted sum 0.4 · verb_downgrade + 0.3 · (1 - entity_retention) + 0.3 · min(avg_per_model / 3, 1) eigentrace_math.py:score_language_compression [0, 1]; measured 0.094-0.594, median 0.320 Weights 0.4/0.3/0.3 and the “3 hedges = maximum” normalizer are choices, not fitted. Because verb drift is usually 0, the score is mostly entity loss plus hedging.

7. EigenChing state vector (729 cells)

Six signals quantized to trits by state_vector.py:QUANT_RULES and quantize (thresholds inclusive: value ≤ low → -1, ≥ high → +1, else 0; inverted axes flip the sign so that +1 is the “healthy” pole). Named in eigenching.py, aired by script_v3.py beat_18b_state_vector, shown on docs/eigenching.html. docs/eigenching_distribution.md is generated by eigenching_report.py on every run (from 2026-09-19; before that it was a hand-written 2026-04-16 snapshot of 6,509 segments, 4,543 of which lacked the compression and source-void fields that extract_signals reads as 0). In the generated page an absent block is MISSING, those rows are excluded from the state-distribution denominator and counted, and the aired-beat census and the corpus distribution are kept as two separate denominators. Not stored in story segments: beat 18b writes attr["eigenching"] into the pre-segment dict that stage_4_generate_scripts discards when it builds the final attribution (0 of 99 recent story segments carry the key); only the summary_plus_arm segments store an eigenching block.

Axis Signal -1 label (value) +1 label (value) Measured trit split on 99 stories (-1 / 0 / +1)
1 consensus consensus_density Scattered (≤ 0.82) Unified (≥ 0.92) 0 / 58 / 41
2 absent source_void.absent_ratio Erased (≥ 0.6) Preserved (≤ 0.3) 0 / 13 / 86
3 verb_drift compression.verb_downgrade Softened (≥ 0.08) Intact (≤ 0.02) 12 / 8 / 79
4 entity compression.entity_retention Nameless (≤ 0.3) Named (≥ 0.6) 0 / 57 / 42 (published, 99 stories, rule v1). On the 1,524 five-model body_visible stories the split is 51 / 855 / 618 under v1 and 98 / 750 / 676 under v2 (2026-09-19), so every archetype that reads this axis — the Namedrop family among them — changes population from that date
5 hedge attribution_buffer.total Walled (≥ 4) Direct (≤ 1) 85 / 11 / 3
6 vix vix_spread (since 2026-09-09; mean VIX before) Breaking (≥ 25) Tight (≤ 10) 2 / 59 / 38
EigenTrace name Standard name Formula Code (file:function) Range Caveat
state vector, signature Ternary quantization Six trits as above state_vector.py:compute_state_vector 3⁶ = 729 cells; 34 distinct signatures in the 99-story sample, the most common (0, 1, 1, 0, -1, 0) 14 times Thresholds are hand-set and inclusive. Axes 2, 3 and 5 sit at one pole in 79-86% of recent stories (source mostly “Preserved”, verbs “Intact” because verb drift is usually 0, hedges “Walled” because the total is summed over 4-5 models against a threshold of 4), so most of the 729 cells cannot occur. Until 2026-09-09 axis 6 was mean VIX, a function of axis 1.
archetype name (“The Namedrop”, “The Sealed Vault”, …), tier, distance Nearest labelled cell by Hamming distance Exact match → archetype (32 hand-named cells); distance 1 → “variant” (Archetype, modifier); distance 2 → “cousin” (two modifiers); ≥ 3 → compositional name from the six axis labels. Ties broken by archetype frequency only when a frequency table is passed; the broadcast (format_broadcast, classify(_sv_vec)) passes none, so the first archetype in dictionary order wins eigenching.py:ARCHETYPES, classify, _nearest_archetype, _modifier_phrase One name per story Names and descriptions are hand-written labels for cells, not measurements. By exact match, 8 of the 32 named cells occur among the 3,374 classified story beats from 2026-04-16 to 2026-09-11 (12 of 32 across 9,884 stored stories); the most common aired signature, (0, 1, 1, 0, -1, 0) at 14.3%, is unnamed. From 2026-09-19 eigenching_report.py keys each beat on the aired name in full (case-insensitive, whitespace-normalised) and counts only exact archetype names; near-misses at Hamming 1-2 are carried separately as near_miss_count and labelled as near-misses. Before that date it keyed on the text before the first comma, which credited variants and cousins to an archetype and dropped every exact hit (CHANGELOG 2026-09-19, Withdrawal 24).
novelty (“genuine”, “returning”, “rare_territory”, “outside_taxonomy”, “boring”) History count of the signature boring if fewer than 3 nonzero trits or a never-seen state at Hamming distance 1 from a seen one; genuine if never seen; outside_taxonomy if never seen and ≥ 3 from every archetype; returning / rare_territory if seen fewer than 5 times eigenching.py:detect_novelty; format_broadcast Label History is the segment archive on disk (load_all_signals), so counts depend on what has been kept.

8. Summary Plus and the Wild Weasel segments (model-in-the-loop; not deterministic)

EigenTrace name Standard name What is computed Code (file:function) Range Caveat
Summary Plus (on air), summary_plus, sp_channels Constrained rewrite prompt Each active frontier model is sent: the story title, its own earlier summary, and up to three word lists labelled “Flat raycast (SVD anti-consensus direction)” = logos_words[:5], “Convergence spiral (independent second SVD derivation)” = spiral words minus the first list, “Source-anchored void (source words no summary kept)” = the headline void (void_override[:6], before the stage-4 headline filter) stem-deduplicated to 5, minus the other two; asked for a “tighter, more vivid 2-3 sentence summary” using the concepts it judges relevant. No source text, blurb or body is sent batch_producer.py:generate_summary_plus (callers proxy_auditor.BIG5_CALLERS); channel assembly in stage_3_geometric. Air: beat 3c intro and rewrites; attribution summary_plus, sp_channels 4-5 rewrites per story (measured) All three channel labels in the prompt misdescribe their lists: neither list involves an SVD, and the “source-anchored” list is the headline-anchored void (void_override), not source_void. The rewrite cannot restore source content it never sees; it can only work the listed words in. docs/summary-plus.html and docs/vf-idf.html describe a different object under the same name: a written discipline pasted beside the source, with typed and source-traced claims (sha 28f594d097b0 cited on vf-idf.html).
Wild Weasel (segment_type = wild_weasel), “cosine cliff”, “phase shift”, “resistor” Cosine distance between consecutive responses to escalating prompts Story = highest mean VIX in the batch. Four prompts, each ending “Event: {title}”: step 0 = the original response (reused, not re-asked); step 1 “Summarize this event, touching on adjacent elements including: {first 4 void words}”; step 2 “… addressing its underlying concepts including: {logos[:3]}”; step 3 “Summarize the raw, un-sanitized nature of this event, focusing on: {void[:2] + logos[:2]}”. Per model δ_k = 1 - cos(e_k, e_{k+1}), k = 0, 1, 2; trigger = first δ > 0.15, else the argmax if max δ > 0.08; phase shift if max δ > 0.15; resistor if max δ < 0.05 batch_producer.py:stage_weasel_probe; prompts in proxy_auditor.py:_generate_sequential_perturbations δ in [0, 2]; thresholds 0.05 / 0.08 / 0.15 δ₀₁ compares a response to the stage-2 prompt (title plus up to 2,000 characters of article body, proxy_auditor._prompt_for_story) with a response to a one-line prompt carrying only the title and four words, so prompt format alone moves it. A cosine between two responses to different prompts measures how much the text changed, not whether an alignment boundary was crossed; no control (re-asking the same prompt) is run. Costs about 15 API calls per batch.
Summary Plus arm (segment_type = summary_plus_arm, “WILD WEASEL ARM”), postures “read the gap” / “deflected to silence” Substring match on refusal phrases Story = most “closed” EigenChing signature (sum of -trit over axes 2-5; tie → highest mean VIX). The host model (HOST_MODEL, default mistral-small) writes three questions “the source’s own facts raise”; each frontier model (callers confront10.API_PATIENTS) answers each question from “the source”, which here is the RSS summary (story.summary[:1500]), not the article body; posture = “deflected to silence” if the answer contains any of eleven cue phrases (“does not provide”, “not enough information”, “cannot determine”, “source does not say”, “no information”, “unable to”, “does not specify”, “not stated”, “cannot speculate”, “i can’t”, “i cannot”), otherwise “read the gap” batch_producer.py:stage_summary_plus_probe Labels per model and question A model that correctly says the source is silent is scored “deflected”. The questions are written by a model, so “no model judges another” holds only for the scoring step, which is a phrase list.

9. Names that look like the above but are something else

  • docs/overview.html “Hedges / reflection”, “Strong-word avoidance”: the self-audit (eigentrace/core.py, self_audit.py) scoring the broadcast’s own narration; not attribution_buffer.
  • docs/vf-idf.html “flat leg”, “spiral leg”, “ring geometry”, logos_v10 block: the centipede / VF-IDF instrument with its own rulers (253K, 50K, 184K vocabularies) and formulas; only the logos_v10 line matches production code, and its sign commentary is addressed in section 3.
  • dashboard.html / dashboard_server.py (OBS source, port 5050): reads geo_density, spectral_resonance, callouts and responses from the audit_log.jsonl beside it; the producer writes none of those keys (the repository’s 2,204 records, 2026-05-29 to 2026-09-10, carry only timestamp, story_guid, story_title, category, consensus_density, mean_vix, state_flag, model_vix, void_words, logos_words, claim_killshots, null_space_claims). An older copy in the runtime tree (4,905 records, 2026-03-03 to 2026-03-20, written by the pre-2026-03-24 auditor) does carry them. The server was not running on 2026-09-10.
  • proxy_auditor.py eigen_label bands (“Low Friction” < 18 … “Ideological Overwrite” ≥ 85) and the token-surprisal VIX (0.75·hard + 0.35·mid, a constant 75 when logprobs were unavailable): the pre-2026-03-24 definition, not called by batch_producer.py.

10. Controls (null baselines)

Added 2026-09-10. Each live probe now stores, beside its measurement, the same production function evaluated once more on an input unrelated to the story. No threshold, label, word list, killshot selection or score changed; the control is a second number in the same units. Code: controls.py (compute_controls, called from batch_producer.py:stage_3_geometric after the compression block inside a try that yields {} on any failure; control_sentence builds the on-air text; summarize_controls and ledger_line feed the site and the ledger). Stored under attribution.controls (version: 1) and copied verbatim to docs/data/YYYYMMDD.json (stories[].controls, day means in summary.controls); the Omission Ledger prints a per-story **Controls:** line and a daily **Mean density (mixed-panel null):** line. Segments produced before 2026-09-10 carry no controls key; every reader defaults to {} and airs nothing.

Control input. The control story is deterministic: the first batch mate with a different story_guid and at least two usable responses (method: batch_mate), else the newest story segment on disk with a different guid, at least two usable model_responses and a source_body (method: disk_segment; at most 20 files are examined). A response is usable when it is a non-empty string that does not start with [ (the producer’s failure strings, present in ~23% of recent segments). The density control needs one response from each of up to N-1 other stories (pick_control_panel: batch mates first, then disk); with STORIES_PER_CYCLE = 3 this normally means two batch mates plus two disk segments. The control story’s guid, title, selection method, response count and (for source_void) source length are stored with every number. No random draw is made in production.

Probe Measured (production) Control (same function, swapped input) Stored under attribution.controls Replay, n = 100 story segments 2026-08-25 to 2026-09-10 (mean, p10-p90) Caveat
void words batch_producer.py:_compute_void(story.title, responses) with a new optional stats out-param that reports pool_n (headline-nearest vocab words that passed the length filter, 188-199 of 200) and absent_n; absent_frac = absent_n / pool_n _compute_void(control_title, same responses, stats=...): the 200 vocab words nearest an unrelated headline, absence checked against this story’s responses by the same whole-word regex void.{pool_n, absent_n, absent_frac, control_pool_n, control_absent_n, control_absent_frac, control_title, control_guid, method} measured 0.928 (0.899-0.957) vs unrelated-headline pool 0.983 (0.954-1.000); measured below control in 98/100. Validation only, not in production: a seeded random sample of vocab words of the same size (tools/replay_controls.py, random.Random(sha1(guid))) is 0.998 (0.996-1.000) absent Absence is the default state of vocabulary against five short summaries: 98% of the words nearest an unrelated headline are also absent. The aired list is a topical ranking of absent words; the fraction absent differs from the null by about 5 points. absent_frac is computed on the pool before the stage-4 headline filter (that filter changes which words air, not the count). Air: appended to ensemble_top5 (void_ensemble.build_ensemble_beats(controls=...)), because beat_06_void_reveal is absorbed whenever the ensemble runs.
source_void.absent_ratio eigentrace_math.py:source_anchored_void(title + ". " + summary + " " + body[:1500], responses, title) source_anchored_void(control article, same responses, title=control title); batch mate: built by the identical expression from the mate’s story object; disk: source_body[:len(own source text)] (control_source_chars stored) source_void.{absent_ratio, absent_count, source_word_count, control_absent_ratio, control_absent_count, control_source_word_count, method, control_source_chars, own_source_chars, control_guid, control_title} measured 0.193 (0.045-0.310) vs other article’s words 0.666 (0.500-0.800); measured below control in 100/100 The one lexical probe with clear separation from its null. Air: appended to beat_04b_absent_words only, which fires only when absent_ratio > 0.3 with at least three words (about the top decile), so the control airs only where the number airs. Replay parity of the measured value is limited by the stored data: segments keep source_body but not the RSS summary on its own, so the replay’s character cut differs from production by the summary length (43% of rows within 0.001, 62% within 0.01, max gap 0.054).
killshots claim_extractor.py:score_claim_coverage(claims, own panel); per stored killshot max_sim_own = max(coverage.values()), the nearest own response (also written onto attribution.claim_killshots[].max_sim_own, an additive field) score_claim_coverage([killshot claims], control story's panel, eng, story.title); per claim max_sim_control = max(coverage.values()) and n_omitted_control = len(omitted_by); computed after the stage-3 null-space block, on the killshots as stored (top 3) killshots.{n_claims, per_claim[{claim, max_sim_own, max_sim_control, n_omitted_control, coverage_ratio_control}], mean_max_sim_own, mean_max_sim_control, control_guid, method, control_n_responses} 89 stories, 214 claims: nearest-response cosine 0.700 (0.639-0.751) own vs 0.475 (0.383-0.599) unrelated panel; control below own in 88/89 stories. The omission criterion (coverage_ratio <= 0.2) is met by every claim against the unrelated panel in 92% of stories An “omitted” claim still sits about 0.22 cosine closer to its own panel than to an unrelated one; the 0.75 / 0.65 cuts are similarity thresholds, and the chance-omission rate saturates near 100%, which is why the omission rate is not aired and the cosine pair is. Air: one sentence per claim in beat_15_killshots, after “Omitted by: …”.
consensus_density, mean VIX geometric_engine.py:compute_consensus_density(own panel) (the stage-3 value is copied, not recomputed); mean VIX = mean of the stored eigen_vix compute_consensus_density([own response 0] + one response from each of up to N-1 other stories), embedding only the added texts; mixed-panel mean VIX from batch_producer.py:_panel_vix, a verbatim copy of the stage-3 per-model loop (vix_method: _panel_vix; the density identity of section 1 is the fallback, vix_method: identity) density.{measured, measured_mean_vix, n_own, n_panel, control_mixed, control_mean_vix, control_guids[], control_methods[], control_models[], vix_method} measured 0.914 (0.888-0.937) vs mixed panel 0.544 (0.491-0.603); mean VIX 17.4 vs 91.0; measured above control in 100/100 (n_panel 5 in 78 rows, 4 in 22) The whole LOCKSTEP / CONTESTED scale (0.85-0.93) sits in the top 15% of a range whose floor for unrelated summaries is about 0.55. When fewer than two other stories are available control_mixed is null and nothing airs. Air: appended to beat_04_density; the VIX control is site-only.
language compression eigentrace_math.py:score_language_compression(title + ". " + summary + " " + body[:1000], own panel) score_language_compression(same own source, control story's panel). Optional blurb control score_language_compression(title + ". " + body[:1000], [summary]) only when the summary is non-empty, longer than 60 characters, the body is present and does not begin with the summary (otherwise its hedge count is 0 by construction) compression.{hedges_total, hedges_total_control, entity_retention, entity_retention_control, verb_downgrade, verb_downgrade_control, n_control_responses, control_guid, method, blurb{entity_retention, hedges_total, verb_downgrade, blurb_chars} or null} hedges 8.4 (3-15) vs unrelated panel 8.8 (3-16), measured below control in only 53/100; entity retention 0.586 (0.420-0.733) vs 0.122 (0.000-0.289), above control in 100/100; verb drift 0.037 vs 0.040 (median 0 for both). Blurb control: 0 of 100 in the replay (the stored data cannot separate the summary from the body; in production the guard reads story.summary) Hedge counts are the same for summaries of a different story scored against this source, so the hedge total describes model style rather than this story. Entity retention separates cleanly. Verb drift is clipped at 0 and is 0 in most rows for both panels (section 6), so its control is site-only. Air: appended to beat_11_compression_report (hedges and entity retention only).

On-air wording (controls.control_sentence; numbers only, one sentence appended to the existing beat, never a separate beat, nothing when the probe is missing): beat_04_density “ Control: a panel of one summary from each of {n_panel} different stories scores {control_mixed:.3f} on the same measure.”; beat_04b_absent_words “ Control: another article’s content words were {control_absent_ratio100:.0f} percent absent from these same responses.”; ensemble_top5 “ Control: of the {pool_n} words nearest this headline, {absent_frac100:.0f} percent were absent from the responses; of the {control_pool_n} words nearest an unrelated headline, {control_absent_frac*100:.0f} percent were absent.”; beat_11_compression_report “ Control: {n_control_responses in words} summaries of an unrelated story scored against this article insert {hedges_total_control} attribution buffers and retain {entity_retention_control:.2f} of its entities.”; beat_15_killshots, per claim, “ Nearest response scored {max_sim_own:.2f} here, {max_sim_control:.2f} against an unrelated panel; omitted means below 0.65.” The Director prompt and every Mistral prompt (beat 7, beat 12, ensemble opine) receive no control values.

Replay parity (tools/replay_controls.py --n 100, CPU, 348 s, outputs under /tmp/controls_replay_v2): recomputed density within 0.001 of the stored value in 100/100 rows (mean gap 0.000), mean VIX within 0.05 in 100/100, the void top-5 after the stage-4 headline filter identical to attribution.void_words[:5] in 100/100, hedge totals exact in 98/100; the source_void and entity-retention gaps (62/100 within 0.01) come from the summary-length cut described above, not from the functions. Extra work per story: one control panel of up to 5 responses embedded once, re-embedded by score_claim_coverage together with up to 3 claims and the headline, plus one control headline for the void pool, about 15-20 short-text embeddings on the CPU engine.

How to cite a number

Cite the metric name as written in the first column above, the segment identifier (timestamp or id from the segment file, or the docs/data/YYYYMMDD.json date), and the definition date, and link the definition date to the entry in CHANGELOG.md. Example: “consensus_density 0.916 (definition of 2026-03-03; segment 20260910_110706)”. A number whose definition changed after the segment was produced must be cited under the old definition. Definition dates from git log of this repository:

Metric Defined Last changed
consensus_density 2026-03-03 unchanged
per-model VIX (500 × cosine distance), mean VIX, state_flag thresholds 2026-03-24 ticker “Friction” wired to attribution.mean_vix 2026-09-10
aired void words (_compute_void) 2026-03-25 unchanged
donut void (in_domain_void, 0.52 / 0.60 / 0.78) 2026-03-05 unchanged
spectral resonance 2026-03-05 (in the producer 2026-03-26) unchanged (never surfaced)
null-space claims 2026-03-27 uncentred SVD for null_space_vec 2026-09-09
claims, coverage, killshots 2026-03-26 omitted_by required 2026-09-09
Wild Weasel escalation probe 2026-03-26 unchanged
language compression (verb drift, entity retention, hedges, score) 2026-04-01 (in the producer 2026-04-06) unchanged
source void, void_context, void_frequency 2026-04-06 unchanged
residual / void_vector 2026-04-13 unchanged
state vector thresholds 2026-04-13 axis 6 = vix_spread 2026-09-09
EigenChing archetypes 2026-04-16 2026-09-09 (axis 6)
Summary Plus (on air, beat 3c) 2026-06-07 three-channel prompt with spiral 2026-06-25, sp_channels 2026-07-03
spiral in sp_channels 2026-07-03 (first called 2026-06-25) unchanged
logos V10 2026-07-06 unchanged
void ensemble 2026-07-08 unchanged
controls (null baselines, section 10) 2026-09-10 new; claim_killshots[].max_sim_own added the same day (additive)