Skip to content

fix(neural): stop the Graph of Trust leaking trust on repeated evidence - #1028

Merged
hyperpolymath merged 2 commits into
mainfrom
claude/graph-of-trust-multiedge
Nov 9, 2026
Merged

hyperpolymath merged 2 commits into
mainfrom
claude/graph-of-trust-multiedge

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

The bug

build_edges/1 emits one edge per verified success. When the same evidence is recorded twice, the PageRank iteration in iterate_trust/4 sees parallel edges:

  • it divided a source's trust by the summed weight of all of its out-edges, duplicates included;
  • it credited each target with only the first matching edge (Enum.find).

So column sums fell below 1 and trust leaked, and how much leaked depended on how many times the evidence had been logged. Tripling an unchanged outcome log moved a recipe's trust from 0.38 to 0.59 and a bot's from 0.89 to 0.94.

I found this while checking the PageRank convergence theorem's premises for #1025. The leak does not break convergence, because the matrix stays column-substochastic, but it makes the scores depend on logging noise.

The fix

  • Rank over the set of edges (Enum.uniq before the adjacency is built), as the Jaccard cross-repo edges already do. Trust then depends on what was observed, not on how often it was logged. graph.edges itself is unchanged.
  • Credit every edge to a target, so the columns of the transition matrix sum to 1 even if parallel edges reappear.

This changes production trust scores. Wherever an outcome log holds repeated (recipe, repo, bot) successes, the scores will move.

The alternative would let repeated successes count with their multiplicity. That would also need the Jaccard cross-repo edges reweighted by count; otherwise duplication still shifts mass between edge kinds. I chose set semantics because the cross-repo edges already work that way. Say if you want multiplicity instead.

Validation

  • New test, recording the same evidence k times leaves every trust score unchanged:
    • fails on main (bot-qualification-fixture: once=0.889 thrice=0.939);
    • still fails with only the summing change (0.980 vs 1.0), because the Jaccard edges ignore multiplicity;
    • passes with this commit.
  • mix test: 2689 tests, 0 failures, 246 excluded.
  • mix format --check-formatted is clean.

Generated by Claude Code

build_edges/1 emits one edge per verified success, so the same evidence
recorded twice arrives at the PageRank iteration as parallel edges. The
iteration divided a source's trust by the weight of all its out-edges,
duplicates included, but credited each target with only the first
matching edge (Enum.find). Column sums fell below 1 and trust leaked, and
how much leaked depended on how many times the evidence was logged.
Tripling an unchanged log moved a recipe's trust from 0.38 to 0.59 and a
bot's from 0.89 to 0.94.

Rank over the set of edges, as the Jaccard cross-repo edges already do,
so that trust depends on what was observed and not on how often it was
logged. Also credit every remaining edge to a target, so the columns of
the transition matrix sum to 1 even if parallel edges reappear.

New test: recording the same evidence three times leaves every trust
score unchanged. It fails on main, and also with only the summing
change; it passes with this commit. mix test: 2689 tests, 0 failures,
246 excluded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0165rGu3tsKmJtevmrdMVyfJ
@coderabbitai

coderabbitai Bot commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

Explain Change →

No actionable comments were generated in the recent review.

Summary

Summary by CodeRabbit

  • Bug Fixes
    • Trust scores now remain consistent when identical verified evidence is recorded multiple times, preventing repeated entries from changing the set of scored items or their scores.
    • Trust calculations now include all positive-weight connections between the same source and destination, rather than counting only one. This ensures scores reflect the full contribution of those connections.

Trust-score calculation now removes exact duplicate edges from adjacency and sums positive parallel-edge weights for incoming trust. A regression test compares scores from four verified observations with scores from those observations repeated three times.

Changes: Trust graph edge handling

Layer / File(s) Summary
Edge handling and trust-score regression
lib/neural/graph_of_trust.ex, test/graph_of_trust_qualification_test.exs
Adjacency construction removes exact duplicate edges. Incoming trust sums all positive-weight edges from a source to a node before applying outgoing-weight normalisation. The regression test checks that repeating verified observations does not change score keys or scores beyond a tolerance of 1.0e-9.

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Possibly related issues

  • Issue 984 concerns deduplicating replays while retaining distinct verified attempts. This change removes identical trust-graph edges, but does not address the broader event-identity distinction.

Possibly related PRs

  • hyperpolymath/hypatia#1002: Changes trust graph construction and supported-node ranking, which produce the scores affected by this change.
  • hyperpolymath/hypatia#1034: Identifies parallel-edge trust leakage in GraphOfTrust, which this change also addresses.
  • hyperpolymath/hypatia#982: Prevents repeated fleet-row imports, which can otherwise add repeated outcome evidence to the trust graph.
Merge Risk: Minimal · up to 00de8

Repeated evidence no longer changes trust scores, and retained duplicate edges do not affect scores after restart. The change is ready to merge after normal checks.

Pre-merge checks: Passed 5

Check name Status Explanation
Title check Passed The title clearly describes the fix for trust leakage caused by repeated evidence, which is the main change.
Description check Passed The description explains the trust leakage, the set-semantics fix, and the reported validation. It is directly related to the changeset.
Docstring Coverage Passed No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 0 functions across 2 files.

Finishing Touches

Generate docstrings

  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

Recent review info

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 8910af7a-0694-4110-9852-91717897d45e
Commits

Reviewing files that changed from the base of the PR and between 142380e and 00de870.

Files selected for processing: 2

  • lib/neural/graph_of_trust.ex
  • test/graph_of_trust_qualification_test.exs

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Recent review details

Context from checks skipped due to timeout: 46

  • GitHub Check: Integration Tests
  • GitHub Check: Escript packaging soundness
  • GitHub Check: CodeRabbit
  • GitHub Check: hypatia / Hypatia Neurosymbolic Analysis
  • GitHub Check: Validate DEED manifests
  • GitHub Check: Empty-linter (invisible characters)
  • GitHub Check: CodeQL Analysis (actions)
  • GitHub Check: Container Security (Trivy) (deploy/Containerfile)
  • GitHub Check: Rust Dependency Audit
  • GitHub Check: Secret Detection (TruffleHog)
  • GitHub Check: Rust License & Ban Check
  • GitHub Check: Secret Detection (Gitleaks)
  • GitHub Check: Generate SBOM
  • GitHub Check: governance / Exemption ratchet
  • GitHub Check: governance / Actions lockfile verify
  • GitHub Check: governance / Language / package anti-pattern policy
  • GitHub Check: governance / JS runtimes — deno
  • GitHub Check: governance / JS runtimes — pnpm
  • GitHub Check: governance / Well-Known (RFC 9116 + RSR)
  • GitHub Check: governance / Code quality + docs
  • GitHub Check: governance / Check Workflow Staleness
  • GitHub Check: governance / Licence consistency
  • GitHub Check: governance / JS runtimes — environment provisions Bun first
  • GitHub Check: governance / UUID v7 conformance
  • GitHub Check: governance / Security policy checks
  • GitHub Check: governance / Debt ratchet
  • GitHub Check: governance / Workflow security linter
  • GitHub Check: governance / UUID v8 conformance
  • GitHub Check: governance / Live Actions policy (credentialed advisory)
  • GitHub Check: governance / Trusted-base reduction policy
  • GitHub Check: governance / Guix packaging policy (Nix retired)
  • GitHub Check: Build AsciiDoc
  • GitHub Check: criterion + baseline gate
  • GitHub Check: E2E — Elixir Scanner Pipeline
  • GitHub Check: Format
  • GitHub Check: stress-test
  • GitHub Check: Test
  • GitHub Check: Clippy
  • GitHub Check: Check
  • GitHub Check: Cargo check + clippy + fmt
  • GitHub Check: Rust Check & Clippy
  • GitHub Check: Detect Haskell tree
  • GitHub Check: Rust Format
  • GitHub Check: k9iser manifest + build
  • GitHub Check: Squabble chains (hard gate)
  • GitHub Check: Build AsciiDoc
Additional comments: 3

lib/neural/graph_of_trust.ex: 2

218-226: LGTM!

259-277: LGTM!

test/graph_of_trust_qualification_test.exs: 1

205-228: LGTM!

@hyperpolymath
hyperpolymath marked this pull request as ready for review November 9, 2026 15:51
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 9, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ❌ Failed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-09T23:34:17.810541Z 00de870 New commits
🔒 Security Review ❌ Failed 2026-11-09T23:32:21.998326Z
We couldn’t complete this review. Comment @codex security review to try again.
00de870 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

This security review couldn’t start because the paying account has exhausted its Codex allowance and has insufficient available credits. The payer can check their balance and add credits in the Codex usage dashboard, then try again. If you do not manage the paying account, contact this repository's admins.

@hyperpolymath
hyperpolymath enabled auto-merge (squash) November 9, 2026 23:32
@chatgpt-codex-connector

Copy link
Copy Markdown

This security review couldn’t start because the paying account has exhausted its Codex allowance and has insufficient available credits. The payer can check their balance and add credits in the Codex usage dashboard, then try again. If you do not manage the paying account, contact this repository's admins.

@sonarqubecloud

sonarqubecloud Bot commented Nov 9, 2026

Copy link
Copy Markdown

@hyperpolymath
hyperpolymath merged commit 3269c7d into main Nov 9, 2026
92 checks passed
@hyperpolymath
hyperpolymath deleted the claude/graph-of-trust-multiedge branch November 9, 2026 23:36
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.

3 participants