Ongoing stories produce multiple aggregates instead of one that updates over time #71
Labels
No labels
Compat/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No assignees
1 participant
Notifications
Due date
No due date set.
Reference
marvin8/yunjin#71
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Some ongoing news stories end up spread across multiple aggregates instead of forming one aggregate that keeps updating. Three recent examples:
The common thread: a story that develops over days — court cases, ongoing incidents — should end up as one aggregate that accumulates later articles, not a fresh aggregate per batch of articles or per day of coverage.
Investigation findings (prod DB copy +
llm_aggregator.py)Investigated against a fresh prod DB copy (taken 2026-10-07) and the incremental pipeline in
src/yunjin/services/llm_aggregator.py.Data first — corrections to two examples in the issue body
Against prod data, two of the three examples do not show fragmentation:
If those read as "a new aggregate per day" in the UI, two other defects plausibly create that impression (both real, below): the aggregate's name is rewritten on every update, so the same group reappears daily under a new title ("…athlete takes witness box" → "…final complainant evidence"), indistinguishable from a fresh aggregate; and the instance on this NUC (port 8080) has had a dead LLM key since Oct 3 (401 on every hourly run), so everything since then is unaggregated there. If any reading was done on that instance, it would show exactly this kind of breakage. (Key renewal is ops, separate from this issue.)
The real fragmentation signal
max(updated_at)over the user's aggregates) means an unassigned article is never reconsidered — stranding is permanent._expire_staledeletes aggregates not updated for 7 days, and their article links go with them. Those articles are then permanently unaggregated (the watermark has moved past them). Too early to observe in prod (DB starts Sep 30), but structural in code.Root cause
The incremental match step is the weak link, not the design concept: matching tiny batches against a huge, summary-drifting topic list fails silently, and no pass ever consolidates the singletons it leaves behind. From-scratch clustering (same LLM, same prompt shape) demonstrably groups well.
Plan of attack (for discussion — nothing implemented)
Decision recorded (2026-10-07)
Items 1, 2, 3 and 5 from the plan of attack will be implemented as one piece of work on this issue:
Item 4 (cap the prompt) is split out to #74 and deferred until after this work, since the cap design depends on the end-state topic universe and has an old-story duplicate risk (see #74 for sequencing).
Implementation has not started; this comment records scope only.
Closed by PR #79 (merged as
709f837): stable aggregate names, membership eligibility, and the nightly consolidation pass — ongoing stories now continue in one aggregate that updates over time.