Skip to content

feat: extract and persist Findings from ToolResults (FactStore Phase 2)#166

Open
luceinaltis wants to merge 2 commits into
mainfrom
feat/157-findings-extraction
Open

feat: extract and persist Findings from ToolResults (FactStore Phase 2)#166
luceinaltis wants to merge 2 commits into
mainfrom
feat/157-findings-extraction

Conversation

@luceinaltis
Copy link
Copy Markdown
Owner

Summary

Closes #157.

Phase 2 of FactStore: the findings table sketched in Phase 1 is now populated. Discrete Finding records are extracted from every successful ToolResult.data dict in ConversationEngine._persist_facts and persisted alongside theses, so ticker-based recall (e.g. "what did we learn about AAPL's earnings last time?") no longer depends on free-text search.

What changed

  • qracer/memory/fact_store.py — new findings table + idx_findings_entity index, plus save_finding() / get_findings() CRUD. Confidence is clamped to [0.0, 1.0] at the store boundary so noisy extractor inputs don't corrupt the schema.
  • qracer/memory/finding_extractor.py — new module. extract_findings(ToolResult) -> list[FindingDraft] with dedicated zero-LLM-cost extractors for trade_thesis, news, and fundamentals. Unknown tools, failed results, and extractor exceptions all yield [] so a bad payload can never break the persistence pipeline.
  • qracer/conversation/engine.py_persist_facts now iterates over every analysis.results entry and persists each extracted draft; per-draft failures are isolated so one bad tool doesn't prevent siblings being saved.

Non-goals (per the issue)

  • No LLM-based extraction — structured-data parsing only.
  • UserPreference extraction is out-of-scope (Phase 3).

Test plan

  • uv run pytest tests/memory/test_fact_store.py tests/memory/test_finding_extractor.py — 35 tests covering Finding CRUD (save, clamp, filter, order, limit, event_date) and extractor behaviour (failure paths, sentiment-weighted confidence, article cap, partial fundamentals, missing-ticker guards).
  • uv run pytest full suite — 798 passed, 14 skipped.
  • uv run ruff check — clean.
  • uv run pyright qracer/memory/finding_extractor.py qracer/memory/fact_store.py qracer/conversation/engine.py — 0 errors.

Manual verification

from qracer.memory.fact_store import FactStore
store = FactStore()  # in-memory
store.save_finding(entity="AAPL", statement="P/E 29", confidence=0.9,
                   source_tool="fundamentals", session_id="demo")
store.get_findings("AAPL")  # -> [Finding(entity='AAPL', ...)]

claude added 2 commits April 14, 2026 14:12
Phase 2 of the FactStore: discrete Finding records are now extracted from
successful ToolResult.data dicts and persisted alongside theses, enabling
ticker-based recall of past insights without relying on free-text search.

- FactStore schema gains a `findings` table + index on entity, plus
  `save_finding()` / `get_findings()` CRUD (confidence is clamped to
  [0,1] at the store boundary so noisy extractor inputs are tolerated).
- New `qracer/memory/finding_extractor.py` parses `trade_thesis`, `news`,
  and `fundamentals` ToolResults into `FindingDraft` records.  Zero LLM
  cost — structured data only.  Failed results, unknown tools, and
  extractor exceptions all yield [] so a bad payload never breaks the
  persistence pipeline.
- `ConversationEngine._persist_facts` loops over analysis.results and
  persists every extracted draft; per-draft exceptions are isolated so
  one bad tool doesn't block findings from siblings.
- Tests: 6 new CRUD tests on FactStore, 14 extractor tests covering
  failure paths, sentiment-weighted confidence, article cap, and
  partial-fundamentals fallback.
Fixes CI code-quality check failure — ruff format wanted to collapse a
two-line call in test_missing_catalyst_skips onto one line.
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.

feat: extract and persist Findings from ToolResults (FactStore Phase 2)

2 participants