Skip to content

fix(graph): dedupe node_rows + use INSERT OR REPLACE to avoid UNIQUE constraint failures — closes #114#127

Merged
Wolfvin merged 1 commit into
mainfrom
fix/redteam-114-unique-constraint-graph-nodes
Jul 1, 2026
Merged

fix(graph): dedupe node_rows + use INSERT OR REPLACE to avoid UNIQUE constraint failures — closes #114#127
Wolfvin merged 1 commit into
mainfrom
fix/redteam-114-unique-constraint-graph-nodes

Conversation

@Wolfvin

@Wolfvin Wolfvin commented Jul 1, 2026

Copy link
Copy Markdown
Owner

What

Fixes RED TEAM issue #114: populate_graph_tables() failed with sqlite3.IntegrityError: UNIQUE constraint failed: graph_nodes.node_id, leaving the graph empty.

Root cause

populate_graph_tables() in scripts/graph_model.py built node_rows from flat_nodes, which can contain duplicate node_id values (file:line:fn) when e.g. a class and its __init__ method share the same line, or when two declarations collide on the same line number. The graph_nodes.node_id column has a UNIQUE constraint, so a bare INSERT raised sqlite3.IntegrityError and rolled back the entire BEGIN EXCLUSIVE transaction — leaving graph_nodes empty.

Fix — two layers of defense

  1. Dedupe node_rows by node_id (last occurrence wins, matching the "last match wins" semantics of the flat registry) before the batch insert. Applied to both populate_graph_tables() and incremental_graph_update().

  2. Use INSERT OR REPLACE instead of bare INSERT so even if a duplicate slips through (e.g. from a prior partial write), the batch succeeds instead of failing the whole transaction.

# Issue #114: dedupe node_rows by node_id.
if node_rows:
    seen: Dict[str, Tuple[Any, ...]] = {}
    for row in node_rows:
        seen[row[0]] = row
    node_rows = list(seen.values())

# ... later ...
conn.executemany(
    "INSERT OR REPLACE INTO {t} (node_id, node_type, name, file, line, extra_json) "
    "VALUES (?, ?, ?, ?, ?, ?)".format(t=GRAPH_NODES_TABLE),
    node_rows,
)

Verification

# Before: scan would fail with IntegrityError, graph_nodes = 0 rows
# After: scan succeeds, graph_nodes = 31 rows (clean_app fixture)

Test suite: 1183 passed, 1 pre-existing failure (#118 — test expectation mismatch, unrelated).

Test plan

  • Scan on clean_app fixture populates graph_nodes (31 nodes, 113 edges)
  • No IntegrityError in logs
  • Full test suite: 1183 passed (no new regressions)
  • CI: full test suite passes

Risk

Low. Dedup uses last-occurrence-wins which matches flat registry semantics. INSERT OR REPLACE is idempotent and the transaction is already wrapped in BEGIN EXCLUSIVE / COMMIT.

…constraint failures — closes #114

Bug: populate_graph_tables() in scripts/graph_model.py built node_rows
from flat_nodes, which can contain duplicate node_id values (file:line:fn)
when e.g. a class and its __init__ method share the same line, or when
two declarations collide on the same line number. The graph_nodes.node_id
column has a UNIQUE constraint, so a bare INSERT raised
sqlite3.IntegrityError and rolled back the entire BEGIN EXCLUSIVE
transaction — leaving graph_nodes empty.

Fix applies two layers of defense:

1. Dedupe node_rows by node_id (last occurrence wins, matching the
   'last match wins' semantics of the flat registry) before the batch
   insert. Applied to both populate_graph_tables() and
   incremental_graph_update().

2. Use INSERT OR REPLACE instead of bare INSERT so even if a duplicate
   slips through (e.g. from a prior partial write), the batch succeeds
   instead of failing the whole transaction.

Verified: scan on clean_app fixture now consistently populates graph_nodes
(31 nodes) and graph_edges (113 edges) without IntegrityError. Test
suite: 1183 passed, 1 pre-existing failure (#118, unrelated).
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@sonarqubecloud

sonarqubecloud Bot commented Jul 1, 2026

Copy link
Copy Markdown

@Wolfvin Wolfvin merged commit 0a0e295 into main Jul 1, 2026
4 of 10 checks passed
@Wolfvin Wolfvin deleted the fix/redteam-114-unique-constraint-graph-nodes branch July 1, 2026 04:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant