Skip to content

fix(llmo): dedupe brand-presence citation counts by execution_id#2881

Merged
Sihalnic-Alin merged 5 commits into
mainfrom
fix/llmo-brand-presence-citation-count-dedup
Jul 22, 2026
Merged

fix(llmo): dedupe brand-presence citation counts by execution_id#2881
Sihalnic-Alin merged 5 commits into
mainfrom
fix/llmo-brand-presence-citation-count-dedup

Conversation

@Sihalnic-Alin

Copy link
Copy Markdown
Contributor

What

Fix for inflated brand-presence citation counts on the Postgres-backed prompt/topic detail endpoints, surfaced via project-elmo-ui's URL Inspector showing implausible numbers like 62 "owned citations" against a prompt with only 1 execution.

Root cause (A): aggregateDetailSources (src/controllers/llmo/llmo-brand-presence.js) counted one citation per brand_presence_sources row, not per distinct execution — a single execution can produce multiple rows for the same URL (e.g. one row per inline citation marker in that execution's answer), inflating citationCount past the number of executions that actually cite it.

Fix (B): carry execution_id through flattenSourceRow (it was being dropped before reaching aggregateDetailSources), then dedupe both citationCount and per-prompt counts in aggregateDetailSources by distinct execution_id — a URL cited multiple times within one execution's answer now counts once. Rows without an execution_id still always count, preserving prior behavior for that (not expected in practice) edge case.

Tests

Added two cases to the aggregateDetailSources suite: no double-counting across multiple rows sharing the same execution_id, and correct counting across distinct execution_ids. Full llmo-brand-presence.test.js suite (515 tests) green locally; eslint clean.

Related

Related to LLMO-1933
Surfaced while investigating project-elmo-ui's URL Inspector "show only cited executions" work (LLMO-1933) — this bug is separate and backend-only; no frontend change needed once this lands. No GitHub issue filed; described directly here.

aggregateDetailSources counted one citation per brand_presence_sources row
instead of per distinct execution, so a URL cited multiple times within a
single execution's answer inflated citationCount past the number of
executions that actually cite it (e.g. 62 owned citations against 1
execution). Carry execution_id through flattenSourceRow and dedupe on it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Sihalnic-Alin Sihalnic-Alin self-assigned this Jul 22, 2026
@github-actions

Copy link
Copy Markdown

This PR will trigger a patch release when merged.

@MysticatBot MysticatBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey @Sihalnic-Alin,

Verdict: Approve - well-scoped bug fix with correct dedup logic and good test coverage.
Complexity: LOW - small, single-service bug fix.
Changes: Deduplicates brand-presence citation counts by execution_id to fix inflated numbers on prompt/topic detail endpoints (2 files).

Non-blocking (2): minor issues and suggestions
  • suggestion: Assert prompts in the distinct-execution test case - since prompt counting is now gated inside the dedup branch, asserting expect(entry.prompts).to.deep.equal([{ prompt: 'q1', count: 2 }]) in the second test locks in that behavior explicitly - test/controllers/llmo/llmo-brand-presence.test.js:6620
  • suggestion: Add a test case for rows without execution_id (null/undefined) to verify they each count independently - this exercises the documented "rows without an execution_id always count" path directly - test/controllers/llmo/llmo-brand-presence.test.js:6572

Skill: pr-review | Model: us.anthropic.claude-opus-4-6-v1[1m] | Duration: 1m 0s | Cost: $3.14 | Commit: b3b4dad9624844b15a585fc4f56d016c582519b8
If this code review was useful, please react with 👍. Otherwise, react with 👎.

@MysticatBot MysticatBot added ai-reviewed Reviewed by AI complexity:low AI-assessed PR complexity: LOW labels Jul 22, 2026
…tation dedup tests

Addresses PR review feedback: lock in the prompts-count assertion for the
distinct-execution-id case, and add explicit coverage for the "no
execution_id" fallback path (each row counts independently).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Extends the existing fetchSourcesForExecutions handler test (mocked DB, no
real Postgres needed) with a second brand_presence_sources row for the same
execution_id + URL, proving the dedup fix holds through the full
request/response path, not just the isolated aggregateDetailSources unit.
Confirmed this fails against the pre-fix code (citationCount: 2) and passes
with the fix (citationCount: 1).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Sihalnic-Alin
Sihalnic-Alin merged commit 49a727f into main Jul 22, 2026
19 checks passed
@Sihalnic-Alin
Sihalnic-Alin deleted the fix/llmo-brand-presence-citation-count-dedup branch July 22, 2026 09:59
solaris007 pushed a commit that referenced this pull request Jul 22, 2026
## [1.677.1](v1.677.0...v1.677.1) (2026-07-22)

### Bug Fixes

* **llmo:** dedupe brand-presence citation counts by execution_id ([#2881](#2881)) ([49a727f](49a727f))
@solaris007

Copy link
Copy Markdown
Member

🎉 This PR is included in version 1.677.1 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-reviewed Reviewed by AI complexity:low AI-assessed PR complexity: LOW released

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants