Skip to content

Conversation

@raydeStar
Copy link

@raydeStar raydeStar commented Dec 11, 2025

Summary

Adds a new "Triangulate News" focus mode that synthesizes news from multiple political perspectives to provide balanced, credible summaries.

Features

  • Multi-perspective sourcing: Gathers news from LEFT, CENTER, and RIGHT-leaning sources
  • Credibility scoring: Uses a 4,500+ entry media bias database to score sources on factual reporting, press freedom, and MBFC credibility ratings
  • Claim extraction & clustering: Extracts factual claims from articles, clusters similar claims, and identifies shared facts vs. conflicts
  • Neutral synthesis: LLM generates a Reuters-style news briefing with proper attribution
  • Visual balance indicator: Shows distribution of sources across the political spectrum
  • Hero images: Displays article thumbnail from highest-credibility source with attribution

New Files

  • src/lib/search/newsTriangulate.ts - Core triangulation logic
  • src/lib/biasLoader.ts - Media bias database loader with credibility scoring
  • src/components/TriangulatedNews/* - UI components for displaying results
  • src/types/newsTriangulate.ts - TypeScript interfaces
  • data/bias/media_bias.csv - Media bias database (4,500+ sources)

Modified Files

  • src/components/MessageInputActions/Focus.tsx - Added triangulation focus option
  • src/components/MessageBox.tsx - Render triangulated results
  • src/lib/search/index.ts - Route triangulation queries
  • src/lib/hooks/useChat.tsx - Handle triangulated response format

Testing

  • Tested with various news queries across breaking news, political topics, and tech news
  • Verified spectrum warnings display correctly when sources are limited
  • Confirmed claim clustering identifies shared facts and conflicts

Screenshots

image image image

Additional Notes

This is an idea that I've been turning around in my head for quite some time - a way to triangulate news, instead of reading from one source and hoping that it is correct. Gathering details from both sides, then agnosticizing the data, we will hopefully be left with facts instead of misleading information.

I've created a CSV file with information on websites and their bias listed. This was a list pulled from online, and I've done additions as well, using AI to vet and give a credibility score. This is all done to algorithmically detect how trustworthy our information is.

All tests were done locally on GPT-OSS 20B - something most LLM hobbyists should be able to run without too much trouble.

This is my first PR - I am a software developer by trade, in the field since mid-2016. Please let me know if I am missing some kind of process here.


Summary by cubic

Added a “Triangulate News” focus mode that compares articles across LEFT, CENTER, and RIGHT sources, clusters claims, and produces a neutral Reuters-style briefing with clear attribution. This improves transparency by showing shared facts, conflicts, and unique angles, backed by credibility scoring from a 4,500+ source database.

  • New Features

    • NewsTriangulationAgent: fetches news, tags lanes via media_bias.csv, balances sources per lane, extracts claims, clusters by similarity, and generates a briefing.
    • UI: TriangulatedNewsResult with hero image, lane balance bar, sources grid, and claim cluster sections (Shared Facts, Conflicts, Unique Angles).
    • New focus mode in MessageInputActions; MessageBox renders triangulated results when present.
    • Credibility scoring (factual, rating, press freedom) with per-domain caps and heuristics for .gov/.edu; logs unknown domains.
    • Query rewrite for follow-ups; suggestions now handle triangulated sources.
  • Refactors

    • searchHandlers wired with triangulateNews agent.
    • More robust suggestion generation in useChat for mixed sources formats.
    • Suppress hydration warning on body to avoid extension-related flicker.

Written for commit f3c6c4f. Summary will update automatically on new commits.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

3 issues found across 15 files

Prompt for AI agents (all 3 issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="src/components/TriangulatedNews/TriangulatedNewsSources.tsx">

<violation number="1" location="src/components/TriangulatedNews/TriangulatedNewsSources.tsx:52">
P1: The `overflow-hidden-scrollable` class added to `document.body` is not cleaned up if the component unmounts while the dialog is open. This can leave the page in a broken scrolling state. Use a `useEffect` cleanup to ensure the class is removed on unmount:

```tsx
useEffect(() =&gt; {
  return () =&gt; {
    document.body.classList.remove(&#39;overflow-hidden-scrollable&#39;);
  };
}, []);
```</violation>
</file>

<file name="src/lib/biasLoader.ts">

<violation number="1" location="src/lib/biasLoader.ts:368">
P1: Synchronous file write (`appendFileSync`) on the request path blocks the event loop. Consider using async I/O (`fs/promises.appendFile`) with a debounced/batched write pattern, or queue unknown domains in memory and flush periodically.</violation>

<violation number="2" location="src/lib/biasLoader.ts:441">
P2: Multi-part TLD handling is incorrect. `news.bbc.co.uk` would look up `co.uk` instead of `bbc.co.uk`. Consider using a proper TLD parsing library (like `psl`) or at minimum checking for common multi-part TLDs (`.co.uk`, `.com.au`, etc.).</violation>
</file>

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Ask questions if you need clarification on any suggestion

Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR


const openModal = () => {
setIsDialogOpen(true);
document.body.classList.add('overflow-hidden-scrollable');
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 11, 2025

Choose a reason for hiding this comment

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

P1: The overflow-hidden-scrollable class added to document.body is not cleaned up if the component unmounts while the dialog is open. This can leave the page in a broken scrolling state. Use a useEffect cleanup to ensure the class is removed on unmount:

useEffect(() => {
  return () => {
    document.body.classList.remove('overflow-hidden-scrollable');
  };
}, []);
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/components/TriangulatedNews/TriangulatedNewsSources.tsx, line 52:

<comment>The `overflow-hidden-scrollable` class added to `document.body` is not cleaned up if the component unmounts while the dialog is open. This can leave the page in a broken scrolling state. Use a `useEffect` cleanup to ensure the class is removed on unmount:

```tsx
useEffect(() =&gt; {
  return () =&gt; {
    document.body.classList.remove(&#39;overflow-hidden-scrollable&#39;);
  };
}, []);
```</comment>

<file context>
@@ -0,0 +1,190 @@
+
+  const openModal = () =&gt; {
+    setIsDialogOpen(true);
+    document.body.classList.add(&#39;overflow-hidden-scrollable&#39;);
+  };
+
</file context>

✅ Addressed in f3c6c4f

// Try without subdomains (e.g., news.bbc.com -> bbc.com)
const parts = cleanDomain.split('.');
if (parts.length > 2) {
const rootDomain = parts.slice(-2).join('.');
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 11, 2025

Choose a reason for hiding this comment

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

P2: Multi-part TLD handling is incorrect. news.bbc.co.uk would look up co.uk instead of bbc.co.uk. Consider using a proper TLD parsing library (like psl) or at minimum checking for common multi-part TLDs (.co.uk, .com.au, etc.).

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/lib/biasLoader.ts, line 441:

<comment>Multi-part TLD handling is incorrect. `news.bbc.co.uk` would look up `co.uk` instead of `bbc.co.uk`. Consider using a proper TLD parsing library (like `psl`) or at minimum checking for common multi-part TLDs (`.co.uk`, `.com.au`, etc.).</comment>

<file context>
@@ -0,0 +1,523 @@
+  // Try without subdomains (e.g., news.bbc.com -&gt; bbc.com)
+  const parts = cleanDomain.split(&#39;.&#39;);
+  if (parts.length &gt; 2) {
+    const rootDomain = parts.slice(-2).join(&#39;.&#39;);
+    if (map.has(rootDomain)) {
+      return map.get(rootDomain)!;
</file context>

✅ Addressed in f3c6c4f

try {
const timestamp = new Date().toISOString().split('T')[0];
const logLine = `${timestamp}\t${domain}\n`;
appendFileSync(UNKNOWN_DOMAINS_LOG_PATH, logLine);
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 11, 2025

Choose a reason for hiding this comment

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

P1: Synchronous file write (appendFileSync) on the request path blocks the event loop. Consider using async I/O (fs/promises.appendFile) with a debounced/batched write pattern, or queue unknown domains in memory and flush periodically.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/lib/biasLoader.ts, line 368:

<comment>Synchronous file write (`appendFileSync`) on the request path blocks the event loop. Consider using async I/O (`fs/promises.appendFile`) with a debounced/batched write pattern, or queue unknown domains in memory and flush periodically.</comment>

<file context>
@@ -0,0 +1,523 @@
+  try {
+    const timestamp = new Date().toISOString().split(&#39;T&#39;)[0];
+    const logLine = `${timestamp}\t${domain}\n`;
+    appendFileSync(UNKNOWN_DOMAINS_LOG_PATH, logLine);
+  } catch {
+    // Silently fail if we can&#39;t write (e.g., permissions)
</file context>

✅ Addressed in f3c6c4f

@ItzCrazyKns
Copy link
Owner

Hey @raydeStar, really appreciate the work you put into this. After reviewing it, we’ve decided not to merge this PR at this time

We’re currently working on a larger update that will let the system reason more autonomously and pull in diverse perspectives on its own. Because of that direction, we don’t see a need for a dedicated triangulation feature in the project right now.

The idea is solid, it’s just something the upcoming architecture will handle more naturally without requiring separate logic

Thanks again for the effort we really do appreciate the contribution

@raydeStar
Copy link
Author

Hey @raydeStar, really appreciate the work you put into this. After reviewing it, we’ve decided not to merge this PR at this time

We’re currently working on a larger update that will let the system reason more autonomously and pull in diverse perspectives on its own. Because of that direction, we don’t see a need for a dedicated triangulation feature in the project right now.

The idea is solid, it’s just something the upcoming architecture will handle more naturally without requiring separate logic

Thanks again for the effort we really do appreciate the contribution

Hey, that's great!! If you need extra hands on a feature, reach out! I am looking to get more on my resume on AI tooling, so I'd be more than happy to help! Thanks for all you do!

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.

2 participants