When a ferry sinks or a central bank moves rates, thirty outlets publish within the hour. A normal RSS reader shows you thirty cards. I build Hushread, an RSS and news reader with no algorithm, and it shows that event once: one story, with a timeline of who reported what and when. This is how that grouping works, and where it went wrong on the way. Every number below is from the code as of October 2026.
Feeds wait in one queue ordered by when they were last pulled, so the feed that has waited longest goes next and a few busy sources can't hog the loop. Feeds people follow are pulled every 15 minutes. A source can be an RSS or Atom feed, a site without a feed, a subreddit, a YouTube channel or a public Facebook page; they all land in the same queue.
Each article is opened and cleaned to reader view (Mozilla Readability for the body, Defuddle for metadata and as the fallback) and dated from the feed or the page. If neither has a date, the date stays blank. Stamping "now" on an undated article makes old news look new, and grouping by time would then join things that never happened together.
Once a minute, new articles are embedded in one batched call. Each article then links to at most one earlier article from the previous 12 hours, when the two are close enough (cosine similarity 0.92 by default). That gives chains: article 12 points to 10, 10 points to 7. A chain is an event.
Chains beat re-clustering for one reason: they are cheap to keep correct while articles keep arriving. Each new article makes exactly one decision, and nothing already linked has to move.
The bug that taught me this: in October 2026 one article, "Netanyahu invites the pilot", sat close to two stories at once. It pulled a 90-article story about a Netanyahu visit to the UAE into a hijacking story. The two stories' centres were only 0.66 alike, while real fragments of the hijacking story sat at 0.73 to 0.86.
The fix was a rule, not a bigger model. One article may merge two stories only when the smaller one is still a fragment (8 articles or fewer, such as early or other-language copies) or when the two stories' centres agree (0.72 or more). Otherwise the article joins one story and leaves the other alone.
"Thirty articles" can be one outlet syndicated thirty times. A publisher is a normalised outlet name plus its domain, and a story's weight is the number of distinct publishers in it. Trending ranks stories by that count, never by clicks, and a story only trends once 5 or more different publishers cover it.
A written Story appears only when an event clears one of two bars:
Stories are written by an AI model from those outlets' reporting alone, and the page says so. Claims are attributed to the outlets that made them, every timeline entry links to the original report, and the byline is "Hushread Stories" with the number of outlets the piece was written from, because no person wrote it. While coverage continues, a Story takes a dated update when at least 2 new articles have arrived, at most every 6 hours.
A story closes after 48 quiet hours or at 7 days old. A closed story is linked to the one it follows when their centres are 0.78 alike or more and it still resembles the thread's first story (0.70). So "the next round of sanctions" joins the sanctions thread, while one football match doesn't swallow the next. Article, story, thread: the event, then the saga. Long stories show up as chapters, each with its own summary.