Skip to content

control_flow_ratio is the corpus's worst metric (33%): it divides a pinned numerator by structural_boundaries, an ungoverned 0-45 vocabulary tally #2770

Closed

Description

@squid-protocol

Same pass as #2769 (2026-09-05, engine 3b3568e0, corpus main 6183c4b). Ranked by consistency score, control_flow_ratio is the worst metric in the corpus — 33%, twenty-five points below the next one. It is currently ungated on the grounds that its denominator is unplanted (#2689 bucket B), which is a correct description of the state and not a resolution: it is still charted, still recorded, and dependency_density (which is gated) is derived from it.

The measurement

total_control_flow_ratio = round(branch_hits / max(branch_hits + linear_hits, 1), 3)   # detector.py:1416

linear_hits is equations["structural_boundaries"]. Over the 46 languages' identical 12-probe program, branch is pinned at 3–5 by the SPEC and structural_boundaries is not pinned at all:

language structural_boundaries language structural_boundaries
solidity 45 shell 16
ada 40 c 14
perl 37 jcl 11
embedded_python 35 haskell 10
swift 33 livecode 7
kotlin 32 yaml 6
javascript / groovy 31 sqlite 4
python / lua / tcl 30–31 scala 3
typescript / php 29–30 dockerfile 2
… … yacc 1
assembly / matlab / ruby 16 m4 / makefile / scheme / markdown 0

A fifteen-fold spread with the numerator held constant. The resulting ratio ranges 0.0 (markdown) to 0.585 (assembly) against a median of 0.094 — sixteen red cells, more than any other metric.

Why: structural_boundaries has no contract either

The rules are not measuring the same thing, and unlike api (#2730), state_mutation (#2765) or encapsulation (#2766) nobody has written down what they should measure. Reading them side by side:

  • solidity/ada/perl/swift/kotlin (30–45) — every declaration keyword, every modifier, every visibility token. The rule behaves like a token-class tally over the language's whole vocabulary.
  • shell (16) — local|readonly|export|declare|typeset|return|exit|source|read|cd|pwd|ls|cp|mv|rm|mkdir|touch, i.e. a list of shell builtins and coreutils commands, plus the pipe operator. That is a command inventory, not a structural boundary.
  • assembly (16) — mov|lea|push|pop|add|sub|inc|dec|mul|div|nop|…, the ISA's non-branch mnemonics.
  • m4 / makefile / scheme / markdown (0) — no rule contributions at all, so their ratio is branch / branch = 1.0 wherever a branch exists.

Three different ideas ("a declaration", "a command", "a non-branch instruction") plus an absence, in a denominator that is supposed to normalise the numerator.

Two consequences worth separating

  1. control_flow_ratio is not comparable across languages and should not be, until the denominator means one thing. Design (D.1): shape-descriptor comparability — the 160 cells decompose into five mechanisms, only 15 of which are a real design question #2689 established this; what it did not do is open the fix.
  2. dependency_density inherits it and is gated. dependency_density = import / (coding_loc × control_flow_ratio) — so a gated metric divides by an ungoverned vocabulary tally. That is why assembly reads 0.063 (−88%) and embedded_python 1.35 (+154%) while their import counts are 3 and 7. Whatever is decided about (1), (2) is a live defect in a metric the gate does read.

The three candidate shapes, in the order they should be considered

(a) Give structural_boundaries a contract and audit 46 languages — the #2730 treatment, third application. The sentence has to be chosen: "a statement-level boundary that is not a decision" is the reading control_flow_ratio needs (branch ÷ all statements = decision density), and it is the reading _slice_by_labels's Mode A consumers already assume. Under it, shell's ls/cp/mv/touch leave the rule, solidity's modifier tokens leave, and the four zero languages gain a real statement count. This is the largest piece of work and the only one that makes the metric mean something.

(b) Change control_flow_ratio's denominator to a structural count that is already language-neutral — coding_loc, or functions_found, or the satellite statement count. Decision density per line is directly comparable and needs no new rule contract. This is cheap and defensible on its own, and it is what the metric's name promises.

(c) Break the dependency_density derivation regardless of (a)/(b), since a coupling measure has no reason to read a control-flow ratio at all. import / coding_loc is the measure its name describes.

(b)+(c) can ship without (a) and would take the worst metric in the corpus from 33% to something readable in one PR; (a) is the honest fix and is the one that also repays #2689's five other consumers of structural_boundaries.

Corpus pairing

structural_boundaries is not planted — SPEC.md deliberately declined to plant it (D.1's withdrawn recommendation, "a per-language vocabulary tally, not a structural count"). Under shape (a) that decision should be revisited in the same PR: a rule with a contract is plantable, and the corpus can hold the denominator equal the way it already holds branch equal. Ledger: control-flow-ratio-denominator-is-a-vocabulary-tally narrows or retires depending on which shape lands.

Part of #2669. Follow-up to #2689 (bucket B) and #2705.

Activity

  1. added
    enhancementNew feature, sensor, or structural signature
    metricsHeuristics, risk exposures, and topological math updates
    core-engineModifications to the central physics and parsing engine
    on Sep 5, 2026
  2. squid-protocol commented on Sep 6, 2026

    @squid-protocol
    OwnerAuthor

    Design pass, with the code read and the corpus measured. Recommendation: (c) first as its own PR — it is a live defect, not a comparability question — then (b) with coding_loc, and (a) split off as its own issue rather than a blocker.

    (c) is now open as #2789. Findings below are the ones that changed the ordering.

    (c) is worse than this issue describes, and it is a discontinuity

    record_keeper.py's logic_loc_denom = max(int(coding_loc * control_flow_ratio), 1). Measured per file on the rosetta corpus (engine d79ff39e):

    lang file coding_loc cfr denom imports dep_density
    python b.py 13 0.000 1 1 1.000
    embedded_python a.py 13 0.000 1 2 2.000
    python main.py 25 0.250 6 1 0.167
    makefile b.mk 14 1.000 14 1 0.071
    yaml main.yml 28 0.750 21 1 0.048

    control_flow_ratio is 0 for any file with no branches, so 4 of the 5 files in every one of the 46 languages divide by the max(..., 1) floor and the column reports the raw import count. assembly 0.063 and embedded_python 1.35 are the two ends of that collapse, not two ungoverned vocabulary tallies. Three failures stack: the branch == 0 discontinuity (up to 20× on one added if, and within a language, so the ledger entry's "fine within one repository" reading does not cover it); int() truncating the product before the floor; and cfr == 1.0 wherever structural_boundaries never fires, which silently makes the denominator coding_loc — the right answer by accident.

    The fix needed no new design. analysis_lens.ENGINE_CONSTANTS already says "every per-file density equation divides by max(coding_loc, EVIDENCE_MASS_FLOOR)" (#2655); dependency_density was simply missed by it, six lines below the sibling func_internal_density that got the per-function analog in #2705.

    Also worth recording: the corpus's current 82.6% consistency on dependency_density is a floor artifact, not evidence of health — the denominator is the constant 1 for most cells. It goes to 95.6% under the fix.

    The second site this issue does not name

    security_auditor.py:359 carries the same coding_loc * control_flow_ratio idiom:

    logic_loc = max(int(round(coding_loc * cfr)), 1)
    safe_denom = max(logic_loc, coding_loc, 1)

    cfr is bounded [0, 1] by construction, so logic_loc <= coding_loc always and safe_denom could never select logic_loc — that half is dead and #2789 writes it as the max(coding_loc, 1) it always computed. logic_loc survives as log_logic_loc, an input to the pre-trained model, carrying the same branch == 0 discontinuity into a scored feature. #2789 leaves it alone and records the defect in place: redefining a trained input is a retrain, per the frozen func_internal_density: 0.0 precedent 20 lines down. Someone should decide whether that retrain is worth scheduling.

    (b): take it, with coding_loc, and don't wait for (a)

    Two arguments.

    (a) converges on (b) anyway. The contract sentence proposed above — "a statement-level boundary that is not a decision" — makes branch + structural_boundaries ≈ the file's statement count. That is a regex-approximated, 46-language-audited reconstruction of a number prism.py:318 already computes exactly and language-aware: coding_loc, taken off final_code after the language's own comment stripping (not the crude #/// fallback in _calculate_block_metrics). Spending the #2730 treatment to rebuild coding_loc badly is the wrong trade for this metric.

    Measured, from docs/bias_data.json through bias_report._row_stats' own ±25% band:

    denominator consistency
    branch + structural_boundaries (current) 34.8%
    coding_loc 68.9%
    max(coding_loc, 50) 68.9% (constant rescale)
    functions_found 70.5% — but that is avg_func_complexity, already its own column at 67.4%

    Worst-in-corpus to mid-pack in one line, no rule audit. Take the floored form for consistency with the #2655 doctrine; do not add a second avg_func_complexity.

    Two implementation points not in the issue text:

    • There are two definitions — file-level detector.py:1447 and per-function detector.py:6927 — and they must move together, or the control_flow_ratio and cf_ratio columns stop meaning the same thing. The per-function one wants max(loc, FUNC_EVIDENCE_MASS_FLOOR), the 12 that already exists.
    • The per-function one feeds angle = 22.5 + (1.0 - control_flow_ratio) * 67.5 (detector.py:6928). Today cfr is bounded [0, 1]; branch / coding_loc is not — a one-line if/else gives 2.0 — and the angle would go under its 22.5 floor. Needs an explicit clamp plus a test pinning the bound.

    Blast radius is angle for every function in every golden master, plus tel_cfr, the archetype vector at signal_processor.py:598, and the security feature row — which is why it wants to be its own PR. (#2789, by contrast, changed no golden master in either mode: dependency_density is sqlite-only.)

    (a): keep it, unblock it

    structural_boundaries still deserves the contract on its own merits — a SIGNAL_SCHEMA slot, charted as "Sequential Logic Declarations" (analysis_lens.py:1270), one of the statistical auditor's 32 signal keys, in llm_recorder's structure_keys, and an input to log_density_hit_structural_boundaries. shell's ls|cp|mv|rm|touch is a coreutils inventory and should go regardless. But once (b) lands, control_flow_ratio no longer reads it, so the audit leaves the critical path and can be scheduled against #2669 alongside the other rule contracts.

    Under (b), control_flow_ratio also becomes plantable (branch is already pinned, coding_loc is measured), so control-flow-ratio-denominator-is-a-vocabulary-tally retires rather than narrows and the metric can leave ungated_metrics.

    Two caveats on the numbers above

    • docs/bias_data.json predates the assembly/agc_assembly: branch counts unconditional transfers — 23 of 25 hits are call/ret/jmp, not decisions (#2545's shape) #2764 assembly re-bless — it still carries branch 24 / cfr 0.585 for assembly, where a live scan now reads main.asm at 0.214. The current-vs-candidate comparison is like-for-like so the ranking conclusion holds, but the exact percentages will shift on regeneration, and this issue's "0.585 (assembly)" headline is stale.
    • The ledger entry's standing defense — "gitgalaxy compares control_flow_ratio between files WITHIN one repository, where the vocabulary is held constant" — is weaker than it reads. security_auditor._build_feature_frame one-hot encodes language but does no per-language normalization and no groupby, so in a polyglot repo the vocabularies are not held constant. Worth noting in the entry either way.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    core-engineModifications to the central physics and parsing engineenhancementNew feature, sensor, or structural signaturemetricsHeuristics, risk exposures, and topological math updates

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions