๐Ÿงฌ TruthDNA โ€” Misinformation Tracker

Inspiration

It started with a WhatsApp message.

My family group chat lit up one morning with a health claim โ€” something about a common food causing cancer, shared by a well-meaning relative who genuinely believed it. Within hours it had been forwarded hundreds of times across other groups. By the time I tracked down the original source and debunked it, the damage was done. Nobody reads the correction. Everyone remembers the claim.

That moment stuck with me. Misinformation doesn't spread because people are gullible โ€” it spreads because verification is too slow and too hard. The World Economic Forum ranked misinformation the #1 global threat in 2026, above climate change and armed conflict. As of today, $62\%$ of all online content is estimated to be false or misleading. And with AI now capable of generating convincing fake papers, deepfakes, and news articles at scale, the problem is accelerating faster than any human fact-checker can keep up.

I wanted to build something that fights misinformation the way misinformation itself spreads โ€” fast, autonomous, and continuously improving.


What I Learned

Building TruthDNA taught me that the hardest part of AI agent development isn't the model โ€” it's the context engineering.

Getting GPT-4o-mini to return a reliable verdict wasn't just about prompting. It required:

  • A calibration layer that checks whether source evidence directly supports the claim before accepting the verdict
  • A confidence weight system that tracks which entity types historically appear in misinformation

The weight score for each entity type is computed as:

$$w_e = \frac{N_{\text{misinfo}}(e)}{N_{\text{misinfo}}(e) + N_{\text{true}}(e)}$$

Where $w_e \in [0, 1]$ represents how misinformation-prone claims mentioning entity type $e$ tend to be. A score of $w_e > 0.7$ triggers an automatic score boost during analysis:

$$S_{\text{final}} = \min\left(100,\ S_{\text{base}} + \sum_{e \in E} \mathbb{1}[w_e > 0.7] \cdot w_e \cdot 15\right)$$

I also learned that graph databases fundamentally change how you think about knowledge. In a relational database, asking "which claims share the same entities?" requires expensive joins. In Neo4j, it's a single Cypher traversal. That architectural insight unlocked mutation detection โ€” the ability to see when the same actors and technologies appear across multiple coordinated false claims.


How I Built It

TruthDNA is a fully async Python pipeline with six stages, each powered by a different sponsor technology:

Pipeline Architecture

Input (text or image)
        โ†“
[Reka Vision]     โ†’ Extracts text from screenshots and images
        โ†“
[Pioneer GLiNER2] โ†’ Named entity recognition (12 entity types)
        โ†“
[Query Builder]   โ†’ Adaptive search queries weighted by learned risk scores
        โ†“
[Tavily]          โ†’ Real-time search across 14 trusted fact-checking sources
        โ†“
[OpenAI GPT-4o]   โ†’ Misinformation scoring (0โ€“100%) + verdict + reasoning
        โ†“
[Neo4j AuraDB]    โ†’ Knowledge graph storage + relationship mapping
        โ†“
Output: Verdict + HTML Report + Learning Update

The Self-Learning System

The learning system runs before and after every claim analysis:

  1. Before โ€” update_confidence_weights() queries all past Claim nodes and their linked Entity nodes, computing $w_e$ for each entity type and storing the result as Weight nodes in Neo4j

  2. Before โ€” get_improvement_suggestions() finds semantically similar past claims using sequence matching, applying a $+10\%$ score boost if a similar claim was previously verified as misinformation

  3. After โ€” log_query_effectiveness() updates QueryPattern nodes with success rates, tracking which search strategies reliably return verifiable sources

  4. After โ€” log_learning_event() increments the analysis_count property on every entity node involved in the claim

Over time, the system builds a living knowledge graph where:

  • (:Claim) nodes store verdicts, scores, and reasoning
  • (:Entity) nodes accumulate analysis history
  • (:Weight) nodes encode learned misinformation risk per entity type
  • (:QueryPattern) nodes track which search strategies work best
  • [:MENTIONS] relationships connect claims to entities
  • [:CONTRADICTS] relationships link claims to debunking sources

Stack

Component Technology
Entity Extraction Pioneer GLiNER2 API
Vision / OCR Reka Flash
Real-Time Search Tavily
AI Scoring OpenAI GPT-4o-mini
Knowledge Graph Neo4j AuraDB
Web UI Streamlit
Async Runtime Python asyncio + httpx

Challenges

1. Async Architecture Across Mixed Sync/Async Drivers

Neo4j provides both a sync driver (GraphDatabase) and an async driver (AsyncGraphDatabase). The learning system uses the sync driver (for CPU-bound similarity calculations run in thread executors), while the graph storage layer uses the async driver. Keeping these two in sync โ€” pun intended โ€” without blocking the event loop required careful use of run_in_executor and strict separation of responsibilities.

2. Calibrating the Scorer Without Ground Truth

The biggest challenge was preventing the system from being overconfident. GPT-4o-mini would sometimes return MISINFORMATION with HIGH confidence for claims where the search results were only tangentially related. I built a calibration function that checks direct evidence overlap between the claim and search results using tokenized word intersection:

$$\text{overlap_ratio} = \frac{|\text{terms}{\text{claim}} \cap \text{terms}{\text{source}}|}{\max(|\text{terms}_{\text{claim}}|, 1)}$$

If $\text{overlap_ratio} < 0.45$ and $|\text{shared terms}| < 3$, the verdict is downgraded to UNVERIFIABLE regardless of what the model returned. This single rule dramatically improved verdict reliability.

3. Cold Start Problem

A self-learning system that starts with no data is useless for a demo. I solved this by building a seed script that pre-populates AuraDB with 12 historical claims, 18 entities, 22 relationships, and 5 query patterns โ€” giving the learning system enough signal to start producing meaningful weight scores and recommendations from the very first run.

4. Running Neo4j in Production

Switching from a local Neo4j instance to AuraDB mid-development broke the connection string format (neo4j:// vs neo4j+s://), the default database name, and the password validation logic. Every file that instantiated a driver had to be updated and tested. A small thing that cost significant time right before the deadline.


What's Next

  • Vector embeddings for claim similarity instead of character-level sequence matching โ€” using Neo4j's native vector index with sentence-transformer embeddings
  • Reka Vision integrated into the Streamlit UI so users can upload images and screenshots directly
  • Mutation scoring โ€” a dedicated metric for detecting when the same false claim has been reworded and is spreading again
  • Browser extension โ€” flag claims inline on Twitter, LinkedIn, and WhatsApp Web before you share them

Built in 4.5 hours for the Context Engineering Hackathon ยท February 2026

Built With

  • async
  • asyncio
  • cypher
  • neo4j
  • pioneer
  • python
  • reka
  • streamlit
  • tavilyai
Share this project:

Updates