You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
length leaks: func_internal_density, avg_func_loc and control_flow_ratio read file length with content and tier held equal (rosetta F.1 design pass) #2705
Found by the length-leak check added to keyword-rosetta's bias_report.py in gitgalaxy#2669 F.1. Design pass requested (T1), in the #2655 shape: no engine edit until the shape is approved.
What the check does
The rosetta corpus is one 12-probe program written in 46 languages, at 46 lengths (coding_loc from 4 to 19 lines per file; every shell is under the 50-line evidence-mass floor). For each derived metric, take the languages whose measured inputs for that metric are all inside the green band (content held equal) and that share the engine's scoring tier (_get_tier; the tier-3 languages are largely the short shells, so without this a tier effect reads as a length effect), and rank-correlate the metric against coding_loc. With content and tier held, length is the only thing left to vary, so a strong correlation means the formula is reading length where it should be reading content.
Threshold: |Spearman rho| ≥ 0.6 over ≥ 8 languages. Engine a334839, corpus main, 2026-09-04.
What it found
metric
languages (tier3)
rho
inputs held in band
where length enters
func_internal_density
11
−0.96
branch, args, func_start
avg_func_complexity / avg_func_loc (record_keeper.py ~L487) — the denominator is length by construction
avg_func_loc
29
+0.92
func_start
loc / functions_found — length by definition
control_flow_ratio
21
−0.67
branch
branch / (branch + structural_boundaries) (detector.py ~L1288); structural_boundaries is a per-language token tally that grows with the file
Weak (0.4 ≤ |rho| < 0.6), reported but not asserted: risk_cognitive_load −0.58 (n=8), risk_tech_debt −0.58 (n=16), cog_raw −0.55 (n=9), risk_verification +0.48 (n=25, no LOC term located), classes_found −0.41 (n=31, nothing held). Note that cog_raw read −0.63 before tier was held equal and dropped to weak after: most of what looked like a length leak there was #2653's irc / mass_loc term. Everything under _mass_loc (cog load, safety, state flux, tech debt) is floored at 50 by #2655, so no rosetta shell should carry a length term through those densities at all — the residual weak correlations are either an unheld input (concurrency, reflection_metaprogramming are not cached) or the per-file mean over four files, and are worth a look but are not the finding.
Why it matters
These three are the per-function morphology descriptors the bias report scores as "the engine describing one program differently depending on the language it is written in". For avg_func_loc that description is tautological: a per-function line count is length, and the corpus cannot plant it. For func_internal_density the same length sits in the denominator, so a language that writes the same 13 probes in fewer lines is reported as denser logic. For control_flow_ratio the branch count is planted at 3 while the denominator is a vocabulary tally that scales with the file — #2689 bucket B already established that planting structural_boundaries cannot equalise it.
On the real-world corpus the same thing holds one level up: two files with identical branch and argument structure score differently on all three purely by line count, which is the length-dependence #2655 removed from the risk densities but not from these recorder-side descriptors.
Options (for the design pass)
Reclassify as length. Treat avg_func_loc as a size measure (it is), and the bias report demotes it to the context group beside coding_loc. Cheapest, but does nothing for the other two.
Redefine control_flow_ratio against a planted-able denominator. Branch per function (avg_func_complexity already exists) or branch per structural boundary kind rather than per boundary token. Changes the metric's meaning; needs the wiki 08-xx pages updated.
Leave the engine alone, ledger the three metrics corpus-side as length-derived. Honest for the rosetta gate, but leaves the real-world length dependence in place.
Recommendation to evaluate first: (2) for func_internal_density, (1) for avg_func_loc, and a decision between (3) and (4) for control_flow_ratio, since #2689 already showed its denominator cannot be planted.
Corpus side
keyword-rosetta PR (F.1/F.2) carries the check, the tiers map in docs/bias_data.json, and the table above regenerated on every corpus push. The three metrics' rosetta cells keep whatever verdict they have today; this issue does not change the gate.
Related: #2655 (evidence-mass floor — the per-file half of this), #2689 (bucket B: structural_boundaries is unplantable), #2653 (tier constants — the confound the check now holds equal), #2669 (Batch F).
Found by the length-leak check added to keyword-rosetta's
bias_report.pyin gitgalaxy#2669 F.1. Design pass requested (T1), in the #2655 shape: no engine edit until the shape is approved.What the check does
The rosetta corpus is one 12-probe program written in 46 languages, at 46 lengths (
coding_locfrom 4 to 19 lines per file; every shell is under the 50-line evidence-mass floor). For each derived metric, take the languages whose measured inputs for that metric are all inside the green band (content held equal) and that share the engine's scoring tier (_get_tier; the tier-3 languages are largely the short shells, so without this a tier effect reads as a length effect), and rank-correlate the metric againstcoding_loc. With content and tier held, length is the only thing left to vary, so a strong correlation means the formula is reading length where it should be reading content.Threshold: |Spearman rho| ≥ 0.6 over ≥ 8 languages. Engine
a334839, corpus main, 2026-09-04.What it found
func_internal_densityavg_func_complexity / avg_func_loc(record_keeper.py~L487) — the denominator is length by constructionavg_func_locloc / functions_found— length by definitioncontrol_flow_ratiobranch / (branch + structural_boundaries)(detector.py~L1288);structural_boundariesis a per-language token tally that grows with the fileWeak (0.4 ≤ |rho| < 0.6), reported but not asserted:
risk_cognitive_load−0.58 (n=8),risk_tech_debt−0.58 (n=16),cog_raw−0.55 (n=9),risk_verification+0.48 (n=25, no LOC term located),classes_found−0.41 (n=31, nothing held). Note thatcog_rawread −0.63 before tier was held equal and dropped to weak after: most of what looked like a length leak there was #2653'sirc / mass_locterm. Everything under_mass_loc(cog load, safety, state flux, tech debt) is floored at 50 by #2655, so no rosetta shell should carry a length term through those densities at all — the residual weak correlations are either an unheld input (concurrency,reflection_metaprogrammingare not cached) or the per-file mean over four files, and are worth a look but are not the finding.Why it matters
These three are the per-function morphology descriptors the bias report scores as "the engine describing one program differently depending on the language it is written in". For
avg_func_locthat description is tautological: a per-function line count is length, and the corpus cannot plant it. Forfunc_internal_densitythe same length sits in the denominator, so a language that writes the same 13 probes in fewer lines is reported as denser logic. Forcontrol_flow_ratiothe branch count is planted at 3 while the denominator is a vocabulary tally that scales with the file — #2689 bucket B already established that plantingstructural_boundariescannot equalise it.On the real-world corpus the same thing holds one level up: two files with identical branch and argument structure score differently on all three purely by line count, which is the length-dependence #2655 removed from the risk densities but not from these recorder-side descriptors.
Options (for the design pass)
avg_func_locas a size measure (it is), and the bias report demotes it to the context group besidecoding_loc. Cheapest, but does nothing for the other two.func_internal_density = avg_comp / max(avg_loc, F)with a per-function evidence floor;control_flow_ratioovermax(branch + boundaries, F'). Same doctrine as_mass_loc, moves golden masters for every function under the floor.control_flow_ratioagainst a planted-able denominator. Branch per function (avg_func_complexityalready exists) or branch per structural boundary kind rather than per boundary token. Changes the metric's meaning; needs the wiki 08-xx pages updated.Recommendation to evaluate first: (2) for
func_internal_density, (1) foravg_func_loc, and a decision between (3) and (4) forcontrol_flow_ratio, since #2689 already showed its denominator cannot be planted.Corpus side
keyword-rosettaPR (F.1/F.2) carries the check, thetiersmap indocs/bias_data.json, and the table above regenerated on every corpus push. The three metrics' rosetta cells keep whatever verdict they have today; this issue does not change the gate.Related: #2655 (evidence-mass floor — the per-file half of this), #2689 (bucket B:
structural_boundariesis unplantable), #2653 (tier constants — the confound the check now holds equal), #2669 (Batch F).