Summary
galaxyscope crashes during forensic report generation on small / sparse Python repositories. The default-value pattern net.get("betweenness_score", 0.0) does not guard against the key being present but set to None, which the centrality producer can return.
Environment
- gitgalaxy: v6.2.0 (from
python -m gitgalaxy.galaxyscope --help)
- Python: 3.14.2
- OS: Windows 11
- Install: cloned
main at 1a326044c4c5a969de28a7fdf5df451bdd1d2afc, run via PYTHONPATH=. python -m gitgalaxy.galaxyscope
Reproduction
Reproduces consistently on at least two unrelated Python repos in the 16–60 file range:
python -m gitgalaxy.galaxyscope /path/to/small-python-repo
Logs show all earlier phases pass cleanly (guardrails, AppSec sensor, auditor, cartographer, synthesis), then:
[INFO] [GalaxyScope.processing] Synthesizing repository metrics across 26 artifacts (22 verified, 4 unparsable)...
[INFO] [GalaxyScope.processing] Synthesis Complete | Volatility Index: 0.00 | Darkness Ratio: 15.4%
[INFO] [GalaxyScope.processing] Generating forensic exposure rankings...
[CRITICAL] FATAL_SYSTEM_COLLAPSE: unsupported operand type(s) for *: 'NoneType' and 'float'
File "gitgalaxy/galaxyscope.py", line 633, in run_mission
report = self.processor.generate_forensic_report(repository_graph)
File "gitgalaxy/physics/signal_processor.py", line 1686, in generate_forensic_report
bottlenecks["contagious_mutation"].append({"path": p, "score": round(btw * flux_risk, 3), ...})
TypeError: unsupported operand type(s) for *: 'NoneType' and 'float'
--db-only does not bypass the failure (the report path runs unconditionally).
Likely cause
Lines 1678–1680:
btw = net.get("betweenness_score", 0.0)
close = net.get("closeness_score", 0.0)
pr = net.get("normalized_blast_radius", 0.0)
dict.get(key, default) only returns the default when the key is missing. If the key is present and the value is None (which the centrality stage appears to emit on graphs below some edge-density threshold), the variables are None, and the btw * flux_risk / close * err_risk / pr * doc_risk multiplications on lines 1686–1688 raise TypeError.
Suggested fix
btw = net.get("betweenness_score") or 0.0
close = net.get("closeness_score") or 0.0
pr = net.get("normalized_blast_radius") or 0.0
(or equivalent if ... is None guards). Lines 1687–1688 share the same vulnerability shape via close and pr; the or 0.0 form fixes all three at once.
Alternatively, fix it upstream so the centrality producer emits 0.0 instead of None for the empty-graph case.
Impact
Small/sparse Python repos — exactly the case where a quick galaxyscope pass would otherwise be a fast first read on a project — currently produce zero output (no JSON, no SQLite written; the failure happens before persistence).
Summary
galaxyscopecrashes during forensic report generation on small / sparse Python repositories. The default-value patternnet.get("betweenness_score", 0.0)does not guard against the key being present but set toNone, which the centrality producer can return.Environment
python -m gitgalaxy.galaxyscope --help)mainat1a326044c4c5a969de28a7fdf5df451bdd1d2afc, run viaPYTHONPATH=. python -m gitgalaxy.galaxyscopeReproduction
Reproduces consistently on at least two unrelated Python repos in the 16–60 file range:
Logs show all earlier phases pass cleanly (guardrails, AppSec sensor, auditor, cartographer, synthesis), then:
--db-onlydoes not bypass the failure (the report path runs unconditionally).Likely cause
Lines 1678–1680:
dict.get(key, default)only returns the default when the key is missing. If the key is present and the value isNone(which the centrality stage appears to emit on graphs below some edge-density threshold), the variables areNone, and thebtw * flux_risk/close * err_risk/pr * doc_riskmultiplications on lines 1686–1688 raiseTypeError.Suggested fix
(or equivalent
if ... is Noneguards). Lines 1687–1688 share the same vulnerability shape viacloseandpr; theor 0.0form fixes all three at once.Alternatively, fix it upstream so the centrality producer emits
0.0instead ofNonefor the empty-graph case.Impact
Small/sparse Python repos — exactly the case where a quick
galaxyscopepass would otherwise be a fast first read on a project — currently produce zero output (no JSON, no SQLite written; the failure happens before persistence).