Lossless Changelog
component

Entity Disambiguation System Implementation

A memo for Sava, the YC trust-administration startup, confidently reported a $19M Series A led by Balderton — except that round belonged to Sava Technologies, a biosensor spinout. The data was real and well-cited, just about a different company.

Changelog - 2025-11-28 (#2)

Entity Disambiguation System Implementation

Type: Bug Fix / Feature Enhancement Priority: CRITICAL Triggered By: Sava memo generation confused target company with Sava Technologies (biosensor company)


Summary

Implemented entity disambiguation across all research and enrichment agents to prevent LLMs from confusing similarly-named companies. The Sava investment memo incorrectly included $19M Series A funding data from Sava Technologies (a European biosensor company) instead of Sava (the YC F25 trust administration platform at savahq.com).


Problem

When generating the investment memo for Sava (trust platform, savahq.com):

  • Section 07 (Funding & Terms) contained detailed, accurate information about a $19M Series A round led by Balderton Capital

  • This data was for Sava Technologies (Imperial College biosensor spinout), a completely different company

  • The confusion passed initial quality checks because the data was real and well-cited - just for the wrong entity

  • Fact-checker flagged inconsistencies but only after significant wrong-entity contamination

Root Cause: Perplexity Sonar Pro and other LLMs default to the most prominent entity with a given name. Without explicit disambiguation context, "Sava funding" returns the better-known biosensor company.


Changes Made

1. cli/improve_section.py

Lines Modified: 153-183, 225

What Changed:

  • Added extraction of company_description, company_url, and research_notes from state

  • Built disambiguation context block when identifying info is available

  • Injected disambiguation context into Perplexity prompt

Before:

PYTHON
prompt = f"""You are improving the '{section_name}' section for an investment memo about {company_name}.

INVESTMENT TYPE: {investment_type.upper()}
MEMO MODE: {memo_mode.upper()}

After:

PYTHON
# Build disambiguation block if we have identifying info
disambiguation_context = ""
if company_description or company_url:
    disambiguation_context = f"""
CRITICAL - ENTITY DISAMBIGUATION:
There may be multiple companies named "{company_name}". You MUST research the CORRECT company:
...
DISAMBIGUATION RULES:
1. ONLY use sources that reference THIS specific company
2. If you find data for a DIFFERENT company with the same name, DISCARD IT
...
"""

prompt = f"""You are improving the '{section_name}' section for an investment memo about {company_name}.

INVESTMENT TYPE: {investment_type.upper()}
MEMO MODE: {memo_mode.upper()}
{disambiguation_context}

2. src/agents/research_enhanced.py

Lines Modified: 134-173, 291-307, 403-412

What Changed:

A. PerplexityProvider.search() - New Parameter

Added disambiguation_context parameter to search method:

PYTHON
def search(
    self,
    query: str,
    max_results: int = 10,
    sources: Optional[List[str]] = None,
    disambiguation_context: Optional[str] = None  # NEW
) -> List[Dict[str, str]]:

B. System Prompt Enhancement

When disambiguation context provided, append to system prompt:

PYTHON
system_prompt = "You are a research assistant providing detailed, cited information..."

if disambiguation_context:
    system_prompt += f"""

CRITICAL DISAMBIGUATION:
{disambiguation_context}

ONLY return information about the CORRECT company. If search results contain
data about a DIFFERENT company with a similar name, DISCARD that data and
state that you could not find information for the correct entity."""

C. Context Building in research_agent_enhanced()

Build disambiguation context from state before searches:

PYTHON
disambiguation_context = None
if company_description or company_url:
    disambiguation_parts = [f"Target company: {company_name}"]
    if company_description:
        disambiguation_parts.append(f"Description: {company_description}")
    if company_url:
        parsed = urlparse(company_url)
        domain = parsed.netloc if parsed.netloc else company_url
        disambiguation_parts.append(f"Website: {company_url}")
        disambiguation_parts.append(f"Domain: {domain}")
    if research_notes:
        disambiguation_parts.append(f"Notes: {research_notes}")
    disambiguation_context = "\n".join(disambiguation_parts)

D. Pass Context to Search Calls

Updated search call to include disambiguation:

PYTHON
if isinstance(search_provider, PerplexityProvider):
    results = search_provider.search(
        query,
        max_results=5 if idx > 1 else max_results,
        sources=research_sources,
        disambiguation_context=disambiguation_context  # NEW
    )

3. src/agents/perplexity_section_researcher.py

Lines Modified: 86-88, 137-155, 200-202, 286-288

What Changed:

A. Function Signature Update

Added company_url and research_notes parameters to build_section_research_query():

PYTHON
def build_section_research_query(
    section_def: Any,
    company_name: str,
    company_description: str,
    general_research: Dict[str, Any],
    memo_mode: str,
    deck_draft_content: str = "",
    company_url: str = "",        # NEW
    research_notes: str = ""      # NEW
) -> str:

B. Disambiguation Block in Query

Added disambiguation block directly into research queries:

PYTHON
disambiguation_block = ""
if company_url or research_notes:
    disambiguation_block = f"""
CRITICAL - ENTITY DISAMBIGUATION:
There may be multiple companies named "{company_name}". You MUST research the CORRECT company:
- Company website: {company_url or 'See description'}
- Description: {company_description}
"""
    if research_notes:
        disambiguation_block += f"- Research notes: {research_notes}\n"

    disambiguation_block += """
DISAMBIGUATION RULES:
1. ONLY use sources that reference THIS specific company
2. If you find funding/revenue data for a DIFFERENT company with the same name, DISCARD IT
3. Cross-reference company website to verify you have the correct entity
4. If unsure, state "Data not verified for this entity" rather than include wrong data
"""

C. State Extraction

Extract URL and notes from state in agent function:

PYTHON
company_url = state.get("company_url", "")
research_notes = state.get("research_notes", "")

D. Pass to Query Builder

Updated call to include new parameters:

PYTHON
query = build_section_research_query(
    section_def=section_def,
    company_name=company_name,
    company_description=company_description,
    general_research=general_research,
    memo_mode=memo_mode,
    deck_draft_content=deck_draft_content,
    company_url=company_url,           # NEW
    research_notes=research_notes      # NEW
)

4. context-vigilance/Disambiguation-Management-across-Agents.md

New File: Created comprehensive specification document

Contents:

  • Problem statement with Sava case study

  • Root cause analysis (4 causes identified)

  • Three-layer defense architecture

  • Implementation specifications with code examples

  • Standardized disambiguation rules

  • Testing protocol

  • Monitoring and alerting guidelines

  • Best practices for data file authors

  • Failure modes and mitigations

  • Pipeline flow diagram

  • Future enhancement roadmap


Verification

Ran improve-section.py on the problematic Funding & Terms section:

BASH
python -m cli.improve_section "Sava" "Funding & Terms"

Result: The system correctly:

  1. Identified the confusion: Output explicitly noted "The existing 'Funding & Terms' section references Sava Technologies, a European glucose biosensor company... However, the company specified for this investment memo is Sava (Sava Lakh, Inc.)"

  2. Discarded wrong-entity data: Did not repeat the $19M Series A or Balderton Capital information

  3. Used correct sources only: Citations reference savahq.com and YC profile only

  4. Admitted data gaps honestly: "No Series A funding information is publicly disclosed in available sources"


Data File Best Practices

For companies with common/ambiguous names, ensure data/{Company}.json includes:

JSON
{
  "description": "Specific description with unique identifiers",
  "url": "https://official-website.com",
  "notes": "Research X company only, NOT Y company (describe confusion risk)"
}

Example (Sava):

JSON
{
  "description": "Sava is a financial and legal technology platform specialized in quickly setting up and managing Trusts",
  "url": "https://www.savahq.com",
  "notes": "Ensure research is about SavaHQ (savahq.com), NOT other companies named Sava."
}

Files Changed

FileTypeLines
cli/improve_section.pyModified153-183, 225
src/agents/research_enhanced.pyModified134-173, 291-307, 403-412
src/agents/perplexity_section_researcher.pyModified86-88, 137-155, 200-202, 286-288
context-vigilance/Disambiguation-Management-across-Agents.mdCreatedFull document
changelog/2025-11-28_02.mdCreatedThis file

  • Full Specification: context-vigilance/Disambiguation-Management-across-Agents.md

  • Hallucination Prevention: context-vigilance/issue-resolution/Preventing-Hallucinations-in-Memo-Generation.md

  • Fact Checker Design: context-vigilance/Anti-Hallucination-Fact-Checker-Agent.md


Next Steps

  1. Re-run Sava memo with disambiguation to verify full pipeline works

  2. Monitor other companies with common names for similar issues

  3. Consider adding automated entity confusion detection to fact-checker

  4. Document known confusable entity pairs for proactive handling


Testing Commands

BASH
# Test section improvement with disambiguation
python -m cli.improve_section "Sava" "Funding & Terms"

# Re-run full memo generation (future test)
python -m src.main "Sava"

# Check for wrong-entity contamination
grep -i "biosensor\|glucose\|CGM\|Imperial College\|Balderton" output/Sava-v0.0.x/2-sections/*.md

Contributors

Implementation by Claude Code (Opus 4.5) with user guidance.