test(build): assert legacy-confidence normalization is idempotent; open 0.9.47

Adds the round-trip idempotency check the deep-dive flagged: after the first
load heals a legacy numeric confidence to INFERRED, reloading the persisted
graph stays silent with a stable score (the warning must not just move one run
later). Dates 0.9.46, opens 0.9.47.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
safishamsi
2026-08-18 15:59:23 +01:00
co-authored by Claude Opus 4.8
parent 5ad221c3f4
commit 74abbfa30c
2 changed files with 27 additions and 1 deletions
+5 -1
View File
@@ -2,7 +2,11 @@
Full release notes with details on each version: [GitHub Releases](https://github.com/safishamsi/graphify/releases)
## 0.9.46 (unreleased)
## 0.9.47 (unreleased)
- Fix: a legacy `graph.json` that stored a numeric edge `confidence` (from a pre-enum version) no longer warns once per edge on every incremental reload; the numeric value is normalized to the `INFERRED` tag with the original float preserved in `confidence_score` (thanks @Trantor-develops).
## 0.9.46 (2026-08-17)
- Fix: node-id normalization is now caseless-stable for combining-mark sequences — `casefold` and NFKC don't commute, so a single pass left `normalize_id(s) != normalize_id(s.casefold())` for inputs like Greek ypogegrammeni followed by a combining accent; normalization now iterates casefold+NFKC to a fixpoint. Letter/digit-bearing ids are unchanged, so existing graphs are not re-keyed.
+22
View File
@@ -228,6 +228,28 @@ def test_legacy_numeric_confidence_links_spelling_reload(capsys):
assert data["confidence_score"] == 0.85
def test_legacy_numeric_confidence_normalization_is_idempotent(capsys):
"""Healing must survive a round-trip: after the first load rewrites the tag to
INFERRED (with the float in confidence_score), a second load of the persisted
graph must stay silent and leave the score stable — otherwise the warning
would just move one run later."""
from networkx.readwrite import json_graph
raw = {"nodes": [{"id": "n1", "label": "A", "file_type": "code", "source_file": "a.py"},
{"id": "n2", "label": "B", "file_type": "code", "source_file": "b.py"}],
"links": [{"source": "n1", "target": "n2", "relation": "calls",
"confidence": 0.85, "source_file": "a.py"}]}
G1 = build_from_json(raw)
capsys.readouterr()
# persist exactly as graph.json would, then reload
persisted = json_graph.node_link_data(G1, edges="links")
G2 = build_from_json(persisted)
err = capsys.readouterr().err
assert "invalid confidence" not in err
d = edge_data(G2, "n1", "n2")
assert d["confidence"] == "INFERRED"
assert d["confidence_score"] == 0.85
def test_node_alias_canonical_field_wins():
"""#2194: when both the canonical field and its alias are present, the
canonical value wins and the alias key is left untouched."""