Skip to content

feat(affected): surface per-edge confidence in affected output (#2352) - #2431

Open
Mustaqeem66 wants to merge 1 commit into
Graphify-Labs:v8from
Mustaqeem66:feat/2352-affected-edge-confidence
Open

feat(affected): surface per-edge confidence in affected output (#2352)#2431
Mustaqeem66 wants to merge 1 commit into
Graphify-Labs:v8from
Mustaqeem66:feat/2352-affected-edge-confidence

Conversation

@Mustaqeem66

Copy link
Copy Markdown

Closes #2352 (text output). See "Scope" below for the --json half.

Problem

affected walks edges in reverse and renders each hit as - label [relation] file:line. Every edge is required to carry a confidence (validate.REQUIRED_EDGE_FIELDS, one of EXTRACTED / INFERRED / AMBIGUOUS), but the reverse walk dropped it on the floor.

The result: a high-confidence extracted call and a speculative inferred edge render identically. On a wide blast radius you cannot tell which hits are facts and which are guesses without opening graph.json and matching edges up by hand — which defeats the point of the command.

Change

affected_nodes() now reads confidence and confidence_score from the same edge dict that already supplies relation and the call-site location. That matters: a node can be reached by more than one edge, so the confidence reported has to belong to the edge whose relation actually passed the filter — not whichever edge happened to be stored first. Piggy-backing on the existing lookup makes that invariant structural rather than something a future edit can quietly break.

Affected nodes for applyToolsAction()
Relations: calls, indirect_call, references, ...
Depth: 2
- run() [calls, EXTRACTED] cli/run.go:L165
- maybe() [uses, INFERRED] cli/maybe.go:L7

Two deliberate calls:

  • An edge with no recorded confidence renders exactly as before (- X() [calls] app.py:L4) rather than gaining an UNKNOWN placeholder. Hand-built and older graphs stay clean, and the tag always means something when it appears.
  • confidence_score is coerced defensively. bool is rejected explicitly, because bools are ints in Python and a naive float() would turn a mis-typed flag into a 1.0 score. Unparseable values degrade to None instead of raising mid-walk; numeric strings are still read.

I also added affected_records() — the structured per-node rows (id, label, depth, relation, confidence, confidence_score, source_file, source_location). It shares the _hit_source() helper with the text renderer, so the two views resolve the call-site-vs-def-line fallback identically and cannot drift.

Scope

Issue #2352 asks for two things. This PR fully delivers the first (inline confidence in text output) and provides the complete data layer for the second.

I stopped short of adding the affected --json flag itself because the argument parsing lives in cli.py, and I did not want to fold an unrelated CLI-surface change into a change that is otherwise contained in affected.py and reviewable on its own. With affected_records() in place the flag is a small, mechanical follow-up. Happy to add it to this PR if you'd rather land the feature in one go — just say the word and I'll push it.

Compatibility

  • AffectedHit's new fields default to None and are appended after the existing ones, so positional construction in existing callers and tests is unaffected.
  • No existing test asserts the exact contents of the [...] tag (tests/test_affected_cli.py uses substring assertions like assert "calls" in out), so those continue to pass.
  • The #BUG1 call-site behaviour is untouched: hits still report the relation SITE when the edge stored one, and honestly fall back to the node's own definition line when it did not.
  • Python 3.10 compatible; no dependency or lockfile changes.

Tests

New tests/test_affected_confidence.py (9 cases) covering: inline tagging of EXTRACTED / INFERRED; unchanged rendering for confidence-less edges; confidence resolving from the correct edge when parallel edges join the same pair (via MultiDiGraph); AffectedHit defaults; record shape and JSON round-trip; relation/depth filter behaviour; empty result for an unresolvable seed; and score coercion including the True-is-an-int trap.

…Labs#2352)

`affected` walks edges in reverse and renders each hit as
`- label [relation] file:line`, dropping the `confidence` field that every
edge is required to carry. An EXTRACTED call and an INFERRED guess rendered
identically, so a blast radius could not be triaged without re-reading
graph.json by hand.

Carry `confidence`/`confidence_score` off the same edge dict that already
supplies `relation` and the call-site location, so all three always describe
the edge actually traversed. The text view now renders
`- run() [calls, EXTRACTED] cli/run.go:L165`; edges with no recorded
confidence render exactly as before rather than gaining a placeholder.

Also adds `affected_records()`, the structured per-node rows behind a future
`affected --json`, built from the same helper as the text view so the two
cannot drift.

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).

Graphify reviewed this change.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).


Graphify review — findings

This PR threads edge confidence data through the affected module's reverse-walk output. It adds two optional via_confidence/via_confidence_score fields to AffectedHit (populated from the traversed edge), a _coerce_score helper, and a new affected_records function that returns structured, JSON-serializable rows mirroring the text view; the text format_affected output now appends the edge's confidence next to its relation tag. The change also introduces a new test file (tests/test_affected_confidence.py) covering text rendering, confidence-source selection across parallel edges, record serialization, filter behavior, and score coercion edge cases.

No blocking issues surfaced. 1 lower-confidence candidate did not survive cross-model review.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 186 functions depend on the 35 functions this change touches.

Health — this change adds coupling hotspots:

  • worse: resolve_seed() — 11 callers, 3 callees
  • worse: format_affected() — 6 callers, 4 callees
  • new: affected_records() — 5 callers, 4 callees

Verification — 186 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 66 function(s) in the blast radius were not formally verified this run

· 2 grounded finding(s) anchored inline below; 1 more finding(s) on lines outside this diff (see the check run).

Comment thread graphify/affected.py
return (data.get("source_file") or None, data.get("source_location") or None)


def affected_records(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regressionaffected_records()

high coupling complexity (Ca·Ce = 20).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread graphify/affected.py
return records


def format_affected(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regressionformat_affected()

6 callers depend on it (afferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

@Mustaqeem66 Mustaqeem66 left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check the latest commit

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.

Expose per-edge confidence in affected output (+ affected --json mode)

1 participant