diff --git a/gitgalaxy/core/README.md b/gitgalaxy/core/README.md index 75bfc99d2..f584b619b 100644 --- a/gitgalaxy/core/README.md +++ b/gitgalaxy/core/README.md @@ -34,6 +34,33 @@ This file categorizes different keyword terms into structural signature counts. * **Fluid-State Language Switching:** Rather than failing on polyglot files, the engine dynamically swaps syntax registries mid-file. It uses scope-aware handshakes to isolate and parse embedded languages (e.g., evaluating SQL execution inside a Python string, or extracting JavaScript logic nested within HTML blocks) without losing context. * **AST-Free Cyclomatic Complexity:** Instead of compiling an Abstract Syntax Tree, this module counts control-flow branch signatures (conditionals, loops, switches) directly from the lexical stream as a fast proxy for cyclomatic complexity, in the same linear-time pass covered by the throughput benchmark above. It does not infer algorithmic (Big-O) complexity or recursion depth from indentation shape -- an earlier heuristic that attempted this was removed after proving unreliable in practice (whitespace geometry doesn't measure algorithmic complexity, and name-occurrence recursion detection false-positived on docstrings, comments, and logging calls). +#### Proximity correlations (`spatial_correlation.py`) — the dampener/amplifier pairs + +After raw counting, six signal-pair correlations adjust the recorded counts based on *where* +hits sit relative to each other — within a character radius **and** (post-#346/#348) inside the +same detected function. These were previously invisible outside the source (#2546 — the #1096 +keyword-rosetta control corpus had to rediscover the flux weighting by micro-repro), so the +full set is documented here. Every adjustment is tallied in the per-file +`mitigation_telemetry`, surfaced in the audit report as "Contextual Mitigations & +Amplifications", so raw counts stay recoverable. + +| Pair (targets ← context) | Radius | Effect on recorded counts | Telemetry key | +|---|---|---|---| +| `high_risk_execution` ← `safety` | 500 | −1 per mitigated hit (the "Silencer Region") | `mitigated_danger` | +| `concurrency` ← `state_mutation` (unless `sync_locks` ≤300 away) | 150 | +5 per race-condition pairing | `amplified_race_conditions` | +| `memory_alloc` ← `cleanup` | 800 | count reduced to unmitigated allocs | `mitigated_memory_allocs` | +| `memory_scraping` ← `exfiltration_camouflage` | 200 | +100 per confirmed pairing | `amplified_leaks` | +| `high_risk_execution` ← `io` | 250 | +1 `sec_tainted_injection` per corroborated RCE | `amplified_rce` | +| `state_mutation` ← `branch` | 150 | **+2 per cascading hit → ×3 net** (the flux weighting, #2546) | `amplified_cascading_flux` | + +The flux row deserves the detail: state mutated near control flow is deliberately weighted ×3 +(feeding `risk_state_flux` / cognitive-load scoring), scoped per mutation to a 150-char radius +within the same function — **not** a blanket per-function toggle. Raw count = +`recorded − 2 × amplified_cascading_flux`. Known amplifier FP: in languages whose branch rules +don't shield string literals (#2535), a branch keyword inside a string creates phantom branch +context and triples real nearby mutations — that fix belongs to #2535. Semantics are pinned by +`tests/core_engine/test_spatial_correlation.py`'s flux micro-repros. + ### 5. `network_risk_sensor.py` (The Topology Mapper) **Role:** Dependency Graphing. Once files are structurally parsed, this module wires them together into a Directed Acyclic Graph (DAG) using their raw import statements. It executes PageRank mathematics to determine each file's absolute **Dependency Blast Radius**, identifies **Architectural Choke Points**, and classifies their **Ecosystem Role** (Producer vs. Consumer). diff --git a/gitgalaxy/core/spatial_correlation.py b/gitgalaxy/core/spatial_correlation.py index c420b9ae6..53dc05f2f 100644 --- a/gitgalaxy/core/spatial_correlation.py +++ b/gitgalaxy/core/spatial_correlation.py @@ -237,7 +237,39 @@ def apply_amplifier_correlations( counts["sec_tainted_injection"] += corroborated_rce mitigations["amplified_rce"] += corroborated_rce - # 6. The OOM Bomb (Cascading State Flux) + # 6. The OOM Bomb (Cascading State Flux) -- the x3 flux weighting (#2546). + # + # SEMANTICS (documented per #2546; mapped by the #1096 keyword-rosetta + # control corpus, ledger entry `state-flux-branch-weighting`): every + # state_mutation hit with a branch hit within 150 CHARACTERS *and* inside + # the SAME function (correlate_scoped; flat-radius fallback for + # module-level code) is "cascading" and gains +2 here -- so it counts x3 + # net in the recorded state_mutation total. State mutated under nearby + # control flow is deliberately weighted as riskier than straight-line + # mutation; this feeds risk_state_flux / cognitive-load scoring + # downstream. + # + # NOT a blanket per-function toggle: the corpus first described this as + # "branch context anywhere in the function triples every mutation", which + # only *looked* true because its probe functions were shorter than the + # 150-char radius. A mutation >150 chars from every branch in its + # function stays x1. + # + # OBSERVABILITY: the amplified count is tallied below as + # `amplified_cascading_flux` in mitigation_telemetry, surfaced per file + # in the audit report ("6. Contextual Mitigations & Amplifications"), so + # the raw hit count is always recoverable: + # raw = recorded_state_mutation - 2 * amplified_cascading_flux. + # + # KNOWN AMPLIFIER FP (#2535, deliberately NOT fixed here): languages + # whose branch rules aren't literal-shielded let a branch keyword inside + # a STRING ("if eval fails, try open") create phantom branch context that + # triples real, unrelated mutations nearby. That is the literal-shielding + # question's highest-leverage scoring consequence and lands with + # whichever direction #2535 takes. + # + # Behavior pinned by tests/core_engine/test_spatial_correlation.py's + # flux-weighting micro-repros -- change those on purpose or not at all. if "state_mutation" in spatial_map and "branch" in spatial_map: _, cascading_flux = correlate_scoped( targets=spatial_map["state_mutation"], @@ -245,7 +277,7 @@ def apply_amplifier_correlations( satellite_ranges=satellite_ranges, max_distance=150, # If state is mutated near heavy branching ) - counts["state_mutation"] += cascading_flux * 2 # Double the raw signal + counts["state_mutation"] += cascading_flux * 2 # +2 on top of the raw hit = x3 net mitigations["amplified_cascading_flux"] = mitigations.get("amplified_cascading_flux", 0) + cascading_flux diff --git a/tests/core_engine/test_spatial_correlation.py b/tests/core_engine/test_spatial_correlation.py index 517709f9f..d0413ceef 100644 --- a/tests/core_engine/test_spatial_correlation.py +++ b/tests/core_engine/test_spatial_correlation.py @@ -1,4 +1,5 @@ from gitgalaxy.core.spatial_correlation import ( + apply_amplifier_correlations, apply_dampener_correlations, correlate_against_ledger, correlate_scoped, @@ -255,3 +256,84 @@ def test_correlate_against_ledger_corroboration_style_reads_mitigated(): _, corroborated = correlate_against_ledger(threat_locations, functions, "api", "db_hooks", max_distance=10) assert corroborated == 1, "API route and DB hook in the same function should corroborate" + + +# ============================================================================== +# TEST: THE x3 FLUX WEIGHTING MICRO-REPROS (#2546) +# Pins Block 6 (The OOM Bomb / Cascading State Flux) exactly as documented in +# spatial_correlation.py -- these encode the deliberate semantics the #1096 +# control corpus had to discover by micro-repro. Change them on purpose or +# not at all. +# ============================================================================== +def test_flux_weighting_branch_within_radius_same_function_triples(): + """One mutation + one branch within 150 chars in the SAME function: + +2 on top of the raw hit = x3 net, tallied as amplified_cascading_flux.""" + satellite_ranges = [(0, 400)] + spatial_map = {"state_mutation": [100], "branch": [180]} + counts = {"state_mutation": 1} + mitigations = _fresh_mitigations() + + apply_amplifier_correlations(spatial_map, satellite_ranges, counts, mitigations) + + assert counts["state_mutation"] == 3, "Mutation near a same-function branch must count x3 net" + assert mitigations["amplified_cascading_flux"] == 1 + + +def test_flux_weighting_no_branch_stays_raw(): + """No branch signal at all: the raw count is untouched (x1).""" + satellite_ranges = [(0, 400)] + spatial_map = {"state_mutation": [100]} + counts = {"state_mutation": 1} + mitigations = _fresh_mitigations() + + apply_amplifier_correlations(spatial_map, satellite_ranges, counts, mitigations) + + assert counts["state_mutation"] == 1, "Mutation with no branch context must stay x1" + assert "amplified_cascading_flux" not in mitigations or mitigations["amplified_cascading_flux"] == 0 + + +def test_flux_weighting_branch_beyond_150_chars_stays_raw(): + """A branch >150 chars away IN THE SAME function does not amplify -- + the weighting is proximity-based (150-char radius), not a blanket + per-function branch-context toggle (the corpus's first description).""" + satellite_ranges = [(0, 1000)] + spatial_map = {"state_mutation": [100], "branch": [400]} + counts = {"state_mutation": 1} + mitigations = _fresh_mitigations() + + apply_amplifier_correlations(spatial_map, satellite_ranges, counts, mitigations) + + assert counts["state_mutation"] == 1, "Branch beyond the 150-char radius must not amplify" + assert mitigations.get("amplified_cascading_flux", 0) == 0 + + +def test_flux_weighting_branch_in_other_function_stays_raw(): + """A branch within 150 raw chars but across a function boundary does not + amplify -- correlate_scoped requires target and 'dampener' in the SAME + satellite (go corpus evidence: 11 = one function's 3x3 + another's 2x1).""" + satellite_ranges = [(0, 150), (150, 400)] + spatial_map = {"state_mutation": [140], "branch": [160]} + counts = {"state_mutation": 1} + mitigations = _fresh_mitigations() + + apply_amplifier_correlations(spatial_map, satellite_ranges, counts, mitigations) + + assert counts["state_mutation"] == 1, "Cross-function branch must not amplify this mutation" + assert mitigations.get("amplified_cascading_flux", 0) == 0 + + +def test_flux_weighting_per_mutation_accounting(): + """Two mutations near branches + one isolated mutation in the same + function: 2 amplified (x3 each) + 1 raw = 3 raw hits -> 7 net, and the + raw count stays recoverable as net - 2 * amplified_cascading_flux.""" + satellite_ranges = [(0, 1000)] + spatial_map = {"state_mutation": [100, 200, 900], "branch": [150]} + counts = {"state_mutation": 3} + mitigations = _fresh_mitigations() + + apply_amplifier_correlations(spatial_map, satellite_ranges, counts, mitigations) + + assert counts["state_mutation"] == 7, "2 amplified (+2 each) + 1 raw should net 7" + assert mitigations["amplified_cascading_flux"] == 2 + raw = counts["state_mutation"] - 2 * mitigations["amplified_cascading_flux"] + assert raw == 3, "Raw hit count must be recoverable from the telemetry"