Learn / Practice

Inside AI Radar — from an RSS response to a published page

AI-APPS · Engineering cases

Trace the site's actual collection windows, daily quotas, deduplication and publishing checks, then diagnose a successful run that produced no visible update.

INTERMEDIATE · 12 MIN · UPDATED 2026-09-22

View count unavailable

On this page 7

“The workflow is green, but the website has no new items.” That observation combines five separate questions: did a request succeed, did any candidate qualify, did files change, did the commit reach the default branch, and did production deploy that commit?

This walkthrough separates those questions using the site's real code. It explains why running every two hours does not imply adding ten items every two hours.

Evidence boundary

This AI-assisted article describes repository commit 558e0a9, not a new production incident investigation. No production latency or filtering accuracy was measured. Quota examples use illustrative inputs. Follow the fixed source snapshot.

1. Follow the boundaries

RSS source
  → request and parse
  → research-topic and technical-mechanism rules
  → window, duplicates, global quota, source quota
  → public records and related coverage
  → content validation and three-locale build
  → Git commit and push
  → deployment system
  → reader-facing page

The first stages select information; later stages deliver it. They need separate evidence.

Boundary Repository entry point Evidence to inspect
Source configuration config/news-sources.json Enabled sources, allowed hosts, daily caps
Response to candidate scripts/news/lib.mjs: parseFeed Publication date, title, source URL, excerpt
Relevance scripts/news/relevance.mjs Topic, mechanism and rejection reason
Batch selection selectItems outside-window, duplicate, daily-limit and other decisions
Public files scripts/news/collect.mjs Actual changes to data/news/items.json
Validation and push .github/workflows/ai-news.yml Build result, commit SHA and push result

All paths refer to the fixed snapshot. Reading Radar does not initiate RSS collection or a model call. The page consumes prepared data, so a feed outage does not directly block a reader's request.

2. Three timestamps, three responsibilities

publishedAt is the source's publication time; collectedAt is the site's ingestion time; the report also records runAt. Backfilled items naturally have different publication and collection dates.

The parser accepts items up to 14 days old. A normal run selects only from the last 48 hours. Manual runs can change window_hours within the parser's range. A wider window cannot recover entries that the feed no longer returns.

The ten-item daily cap uses the UTC collection date, not the publication date or local midnight. UTC midnight is 08:00 in China Standard Time. Runs at 07:50 and 08:10 local time may therefore use different daily quotas.

The current schedule, 35 */2 * * *, targets minute 35 of even UTC hours. It specifies planned triggers, not guaranteed completion times. Check the workflow and selection code.

3. A cap is not a target

Suppose seven items have already been collected today, including five from AIHOT. The site has three slots left and AIHOT has one. Other sources default to two items per day unless their configuration overrides that limit.

Candidates are ordered by research priority, source priority, publication time and ID, then checked individually. AIHOT's source priority bypasses neither relevance rules nor exhausted quotas.

This runnable arithmetic example illustrates remaining capacity, not the complete selection algorithm:

const remaining = (limit, used) => Math.max(0, limit - used);
const siteSlots = remaining(10, 7);
const aihotSlots = remaining(6, 5);
const aihotCanAdd = Math.min(siteSlots, aihotSlots);
console.log({ siteSlots, aihotSlots, aihotCanAdd });
// { siteSlots: 3, aihotSlots: 1, aihotCanAdd: 1 }

A consequential tradeoff: quotas are consumed across runs as items arrive. This is not an end-of-day selection of the best ten items. An accepted morning item is not replaced when a stronger evening candidate appears. Daily volume control and globally optimal daily selection are different objectives; a delayed candidate pool is not implemented here.

4. What the full feed fixes—and what it cannot

A title may say only “new version available,” while the body describes sandbox isolation, test suites or context offloading. AIHOT's full feed supplies those details through transient relevanceText for filtering.

publicNewsItem removes that field before public storage. Source excerpts are capped at 180 characters. Reading full text for relevance does not mean republishing it. The automated workflow currently disables model summaries, so these excerpts must not be labelled AI summaries.

Rules combine topics with mechanisms, such as context engineering with budgeting or compression, and robotics with trajectories or data alignment. Exclusion rules still remove commercial promotion and ranking-only material. These remain rules rather than full semantic understanding: technical articles can mention commercial background, and advertising can contain technical vocabulary.

Passing selection means meeting collection criteria, not establishing factual accuracy. Improve the relevance rules using labelled false positives and false negatives instead of simply loosening them.

5. Deduplication is not semantic clustering

Collection rejects repeated normalized URLs and titles stripped of punctuation and case. Display-level event grouping also considers identical URLs and, within 72 hours, matching titles or supplied content hashes. See the Radar adapter.

There is no embedding-based semantic clustering. A Chinese report and its English official announcement can remain separate events. Supporting a content-hash field also does not imply that the RSS parser produces one for every item.

Within a group, original or official sources are preferred. That preference is not verification: verification needs a checker, date and evidence. Multiple sites repeating the same claim do not automatically establish it.

6. Diagnose “successful but unchanged”

Open that run's news-run-report artifact and proceed in order:

Observation Next check Do not immediately conclude
Source failed HTTP, timeout, parsing, earlier installation steps Every source failed
Source succeeded, inWindow = 0 Latest publication time versus report window The schedule never ran
selected = 0 rejected and notSelected reasons The feed was empty
selected > 0, build failed Content validation and locale build logs Content was published
Build passed, push failed Remote commits and concurrent updates Data reached the default branch
Push succeeded, page unchanged Deployment SHA, production domain and built data Browser caching must be responsible

Collection can succeed when at least one source works, even if others fail. Publishing can also exit successfully because no files changed. Both cases require reading the report.

The concurrency lock covers collection jobs in the same group, not human pushes. If the branch advances during validation, the final push can fail; this workflow does not automatically recompute and retry. Preserve the last verified boundary rather than forcing a push.

7. Apply the pattern elsewhere

Represent a content pipeline as input → selection → storage → publication, with an inspectable artifact at each boundary. Here those are source status, candidate decisions, file changes, commit SHA and deployment.

The next useful engineering step is a small labelled filtering dataset. Daily item count cannot substitute for measuring false inclusions and omissions. Inspect current output in AI Radar or visit the site project.

A note to your future selfBefore you move on, keep one thought of your own.

Your private reading note stays in this browser; it is never uploaded or published. Clearing browser data removes it, so export a copy to keep. This article’s translations share the same note.

KEEP EXPLORING

Related content

  1. PROJECT / 001

    Hohoo’s AI Lab

    A personal knowledge site for public learning, research signals and practice.

    Live
  2. Tutorials

    Calling an LLM with Java 8 — from one request to a conversation

    Three runnable Java demos explain HTTP requests, JSON parsing, timeouts and conversation history.

    15 MINPublished

Which way next?

Based on article relationships and published same-topic content, not random recommendations.

All writing