Repository navigation
File-level K-Means archetype classification silently truncates against its own trained models (115-dim global vs. 83-dim live vector) #1158
Description
🛑 Problem Statement
file_data.file_archetype (telemetry["archetype"]) is assigned by _classify_archetype()
(signal_processor.py:139-166) against two separate pre-trained K-Means models, and both are out
of sync with the live feature vector actually fed into them.
The live vector (signal_processor.py:609-633, raw_vector) is built by iterating
SIGNAL_SCHEMA (skipping indent_tabs/indent_spaces/hardware_bridge/cryptography/sec_*
keys) and appending 7 engineered features (cfr, log_logic_loc, log_imports_out,
log_popularity_in, log_max_func_comp, log_avg_func_args, log_churn). Against the current
SIGNAL_SCHEMA, that's:
SIGNAL_SCHEMA length: 93
filtered length: 76
raw_vector length: 76 + 7 = 83
Global model -- GENERAL_FILE_INFERENCE_MODEL (analysis_lens.py:2155, SCALER_MEDIANS /
SCALER_IQRS / 18-cluster ARCHETYPES_K18 centroids) is 115-dimensional:
SCALER_MEDIANS (file) length: 115
GLOBAL_ARCHETYPES cluster count: 18
file_cluster_0 centroid len: 115
_classify_archetype's distance loop (signal_processor.py:156) uses
range(min(len(scaled_vector), len(centroid_vector))), so it silently compares only the first 83
of each centroid's 115 dimensions -- 32 trained dimensions (~28%) are dropped on every file.
Per-language ("local") models -- SPECIFIC_FILE_INFERENCE_MODEL (analysis_lens.py:4501) --
are 74-dimensional and only exist for 5 of the 59 languages this engine parses (python,
javascript, typescript, c, cpp; confirmed via LANGUAGE_DEFINITIONS). Every other language's
files never get a local_archetype at all (signal_processor.py:654's lang_brain lookup
misses), and even the 5 covered languages compare 74-of-83 live dimensions against their own
centroids -- same truncation bug, smaller magnitude.
This also breaks a shipped, published claim. docs/wiki/03-05-claim-5-file-archetypes.md
("Claim 5") states the file archetype model was trained on 74 dimensions across 10
clusters. The shipped model is now 115 dimensions and 18 clusters (file_cluster_0..17) -- the
model has clearly been retrained since that doc was written, but neither the live raw_vector
construction, the doc, nor (per the sibling repo-level issue) the downstream repo-clustering
feature vocabulary were updated to match.
🎯 Objective
Bring the live per-file feature vector and both trained models (global + per-language) back into
dimensional agreement, and make future drift fail loudly instead of silently truncating.
🛠️ Proposed Implementation
- Reconstruct what the 115-dim global / 74-dim local training vectors actually contained (likely
a superset of today's filteredSIGNAL_SCHEMA-- e.g.sec_*keys currently excluded from
raw_vectorconstruction may have been included at training time, orSIGNAL_SCHEMAhas
grown new keys since). Either updateraw_vectorconstruction to match what the models
expect, or retrain the models against today's 83-dim vector. - Same loud-failure guard as the function-level issue: assert/log when
len(raw_vector) != len(SCALER_MEDIANS)instead of relying onmin()-truncated comparisons. - Decide + document the per-language model coverage scope: is 5-of-59 languages intentional
(highest-volume languages only), or a stalled rollout? If intentional, no code change needed
beyond documenting it; if not, track expanding it as a separate follow-up (not in this issue's
scope -- retraining models needs a real corpus and offline tooling that doesn't currently live
in this repo). - Update
docs/wiki/03-05-claim-5-file-archetypes.mdto reflect the model actually shipped
today (dimension count, cluster count, and the cluster descriptions/DNA -- all presumably
stale if the model was retrained since that doc's numbers were captured).
✅ Acceptance Criteria
- Live
raw_vectorlength matchesGENERAL_FILE_INFERENCE_MODEL's trained dimensionality,
verified by a real test. - Per-language coverage scope (5-of-59) is a documented, deliberate decision, not a silent gap.
- A live/model dimension mismatch fails loudly instead of silently truncating via
min(). -
docs/wiki/03-05-claim-5-file-archetypes.mdmatches the currently shipped model's real
dimension/cluster counts (or is explicitly marked stale/historical).
Activity
squid-protocol commentedon Aug 9, 2026
Part of epic #1160 (K-Means archetype clustering drift, all 3 tiers). Sibling issue: #1157 (function-level), #1159 (repo-level).
fix(metrics): guard archetype classification against silent dimension…
squid-protocol commentedon Sep 16, 2026
Partial progress — assessed against current
main(23d7b8a):Fixed: the global-model truncation. #3061 (merged 2026-09-15) moved
file_archetypeclassification torecord_keeper._classify_file_archetype(), running it after full metric assembly (mirroring the offlineapply_file_clusters) against a rebakedGENERAL_FILE_INFERENCE_MODELretrained on the 83-feature contract — so the live vector and the trained centroids agree by construction, and a dimension mismatch is now structurally impossible rather than silently truncated. Its own numbers:file_archetypepopulates for ~97% of code files, up from ~5%.Not fixed — still open:
SPECIFIC_FILE_INFERENCE_MODEL,local_archetype). This is explicitly called out as deferred in fix(archetypes): classify file archetype from a self-describing brain, post-assembly #3061: "Per-language local micro-species model is still on the old contract →local_archetype/report 'File Archetype' pending its retrain." Confirmed on main:signal_processor.pystill only setslocal_archetype = Noneas a placeholder, and nothing since fix(archetypes): classify file archetype from a self-describing brain, post-assembly #3061 has touched this. Original bug (74-dim model, only 5-of-59 languages covered, same truncation class) stands as described.docs/wiki/03-05-claim-5-file-archetypes.mdstill says "74 distinct dimensions" / "10 archetypes." The actual global model is now on the 83-feature contract (and, per the original report, was already 18 clusters before this retrain) — the doc still doesn't match either the old or new reality. docs(wiki): compositional archetype tower (functions → files → repos) #3029 added a doc cross-link to the new composition-archetype page but didn't correct these specific numbers.Leaving this open, scoped down to items 1 and 2 above. Recommend splitting the remaining local-model retrain into its own tracked follow-up if it isn't already, since it needs the same offline-trainer treatment #3061 did for the global model.
squid-protocol commentedon Sep 16, 2026
Closing this out. The global-model fix (#3061) is the part of this issue we have the corpus data to do properly right now, and it's done — the primary bug (silent dimension truncation) no longer exists.
The remaining per-language ("local") model retrain is real, but needs a broader per-language corpus than we currently have to do credibly. Rather than leave that half-open here, split it off as its own tracked issue: #3085, labeled
status: blockeduntil there's enough data to retrain against.The stale claim-5 doc numbers ("74 dimensions / 10 clusters") are being corrected separately as a docs fix.
squid-protocol commentedon Sep 16, 2026
Docs fix: #3086
docs(claim-5): correct stale 74-dim/10-cluster claim (#1158) (#3086)
fix(archetypes): refuse an inconsistent FILE brain instead of classif…