Repository navigation
UEF small-file normalization isn't achieving its intent — redesign scoring so identical intent scores identically regardless of file size (design pass for Fable) #2655
Description
Design issue, earmarked for a high-reasoning (Fable-class) session per the repo's model-tiering convention — this is an architecture-level scoring question, not a rule tweak. Context: docs/wiki/08-01..08-03 (the Universal Exposure Framework) and the #2560 rosetta classification sweep, whose control corpus (identical planted intent, tiny files) turned out to be exactly the adversarial case for the current small-file handling.
The original intent
Several UEF mechanisms exist to stop tiny files from artificially inflating risk (a 2-coding-LOC file with one hit is 50% "density"): the /(loc + 20.0) padding in _calc_documentation, the loc < 15 special path in _calc_cog_load, sigmoid gating to suppress low-density noise, and per-tier Irc/Fc constants.
Evidence it isn't working (rosetta corpus, 2026-09-02 sweep)
risk_tech_debtswings −50%..+100% across six config/DSL languages whose raw debt plants are byte-for-byte identical (1 planned + 1 fragile) — the swing is purely LOC-normalization shape.- fortran
risk_state_fluxreads +85% while its rawstate_mutationis honest/below-median (−50%) — a direction inversion through the formula (the ledger'samplified_cascading_fluxpath). - The flat
ircterm is divided bysafe_loc, so the smaller the file, the LARGER the implicit-risk floor — one small-file guard is counteracted by another mechanism in the same sum. _calc_api_exposurehard-returns 0 when a file has zeroapihits, discarding itsencapsulationsignal entirely (zig: main file's 4 encapsulation hits contribute nothing).risk_documentation/risk_verificationambers on html/css trace to per-file denominator artifacts (func_start=0 or one-concept-per-file corpus layout), not their own signals.
Option space (deliberately not choosing here)
- Evidence-mass gating: below a minimum coding_loc / function count, emit a neutral tier + explicit "insufficient mass" flag instead of extrapolating density (per-file analog of the mass-weighted averaging 08-01 already uses at directory scope).
- Shrinkage / empirical-Bayes smoothing:
score = (hits + k·prior_density·L̄) / (loc + k·L̄)— replaces the ad hoc+20with a principled estimator; small files converge to the corpus prior, large files to their own density. - Uncertainty-carrying scores: compute a Wilson-style lower bound on hit density and tier on that — a 2-LOC file mathematically cannot reach Red on one hit.
- Density-scale Irc rather than adding it flat, so the tier correction stops blowing up precisely on the small files the other guards try to protect.
- Whatever is chosen: adopt the rosetta corpus as the regression fixture — identical plants should yield near-identical §3 scores across languages and file lengths; today's deviation table becomes the acceptance test.
Related: #2653 (tier membership audit / bias-report treatment of Fc-Irc), keyword-rosetta#25 (census noise), and the sweep's cause-keys tech-debt-score-loc-normalization-artifact, api-exposure-zero-if-no-pub-hits, per-file-doc-api-imbalance.
Activity
squid-protocol commentedon Sep 2, 2026
Additional corroboration from the scripting-family lane:
risk_cognitive_loadswings from python −76% to powershell +91% across the family on structurally similar in-band raw signals — traced to_calc_cog_load's per-file LOC-density division with the hard<15 LOCspecial-path cliff. Shell's terse corpus idiom (b.sh packs an in-band state_mutation=6 into ~17-20 LOC) spikes density near the clamp ceiling with nothing raw-signal-anomalous. Same shape as the tech-debt swings in the issue body: identical/similar intent, wildly different §3 scores, purely from file-length shape. Also from the same lane:_calc_documentationscores a/b/c files 'undocumented' because the corpus documents itself once at its entry point while api mass lives in the imported files — the per-file formula has no notion of documentation living at a module boundary.squid-protocol commentedon Sep 2, 2026
Design pass done (Fable session, 2026-09-02); implementation in #2667.
Decision: an evidence-mass floor. Every per-file density equation now divides by
max(coding_loc, 50). Below the floor a file is scored on its counts, so identical intent scores identically at any length; from 51 LOC up the density regime is byte-identical to before. This one mechanism replaces the six guards that were fighting each other (the<15 → 5.0cog cliff, the two+20pads as small-file guards, theloc/15bureaucracy dampener, unboundedirc/loc, api'smax(total_loc, 10)). Two consistency rules ride along: zero measured evidence scores zero in every tier (Irc corrects, never creates — documentation and cog load now follow the convention the other four Irc-bearing equations already had), and a branchless file carries no cognitive load at any length.Option space, resolved:
mass_floored/evidence_massin telemetry); the neutral tier is not (it would make every corpus file "insufficient" and neutralise half of real files — golden-master median is 51 LOC).+20pad; measured 2.4× residual swing; a pad large enough to matter re-tunes every large-file threshold.irc/loc); unifying the convention for ≥50-LOC files is risk formulas: audit language-tier membership (embedded_python lands tier3) + decide how rosetta bias reporting treats documented Fc/Irc tier constants #2653's call.tests/core_engine/test_uef_length_invariance.pyfeeds the SPEC's planted vectors through the equations (no scan, no cross-repo dependency); the scanned §3 rows become the acceptance test once state-flux ×3 branch-context weighting: undocumented, and phantom-triggered by branch keywords inside string literals #2546/orphan census counts non-function shapes on non-call-graph languages, making orphan→api conversion unauditable #2547 land, because saturation was masking those §2 effects.Two of the observations in the body turned out to be saturation on top of §2 effects, not formula inversions (per-file recomputation from the scan DB reproduces every stored score to 0.000): the config/DSL tech-debt swing is orphan/duplicate synthesis in main/b files (every c file scored exactly 100 in all 45 languages), and fortran's state-flux "inversion" is two saturated files averaged. Full attribution table, corpus evidence (identical-input groups: 0.00 output range on all seven metrics after the change) and the honest bias-report caveat are in the PR body.
New finding for keyword-rosetta: the
PATH_MODIFIERS"config" regex matchesdata/jcl/anddata/makefile/, applying cog ×0.70 to those two corpus folders — a bias source outside both the registry and the formulas; needs a ledger entry or a path rename.feat(metrics): evidence-mass floor replaces the UEF's six small-file …
fix(recorders): floor func_internal_density's denominator at 12 lines…
feat(core-engine): per-file dynamism replaces the flat language irc i…
fix(core-engine): dependency_density is coupling per line, not per co…
squid-protocol commentedon Sep 6, 2026
The corpus's own directory name is still moving two languages' scores
Re-measured 2026-09-06 on engine main
a59ecf6b/ corpus main2038a86, during a cobol/jcl pass over the bias report. This issue is closed; the ledger entry it owns,path-and-extension-modifiers, isdisposition: engine-semantic,still_reproduces: true, and it is the sole verdict on four out-of-band cells that nobody currently owns. Recording the residual here rather than reopening, since the behaviour is deliberate for real repositories — the question is what it does to the corpus that measures it.The entry's own survey names the actionable case:
Two live consequences on the current cache:
cognitive_load × 0.70on all 8 files because the language's directory is calledjcl, which the rule reads as a config directory.risk_cognitive_loadstill reads 1.62 against a 1.30 median — i.e. +25% after a 30% discount; without the modifier the cell would be roughly +79% and clearly red. The corpus is currently reporting a number that is neither the engine's honest reading of the content nor a comparable one.cog × 0.85ona/b/c.cpyfrom the header/declaration extension rule, and itsrisk_documentation(+62%, red) andrisk_safety_score(+26%, amber) are tagged to this entry with no other explanation on file.Both are structurally invisible to any corpus-side fix: the folder must be named after the language, and COBOL copybooks must be
.cpy.What I think is worth deciding, in rough order of cost:
#2669 F.3bands the constant-reading risk metrics against their own strictness stratum. The multipliers are known per file and computable, so the stratum is mechanical._get_locational_multipliersby hand. This is the smallest change and probably the most useful one for anyone reading a real scan, not just the corpus.No action requested on this issue itself — flagging that its residual is load-bearing for cobol and jcl in #2669's sweep, and that nobody owns it since this closed.
fix(engine): the markup handshake's open tag belongs to the host (#2549)
fix(engine): the markup handshake's open tag belongs to the host (#2549…