Skip to content

fix(pipeline): dedupe npm search pagination drift - #11

Merged
rz1989s merged 3 commits into
mainfrom
fix/pipeline-dedupe-npm-pagination
Jul 23, 2026
Merged

rz1989s merged 3 commits into
mainfrom
fix/pipeline-dedupe-npm-pagination

Conversation

@rz1989s

@rz1989s rz1989s commented Jul 23, 2026

Copy link
Copy Markdown
Member

Problem

The live index (?q=pi-subagents) showed duplicate rows — the same package appearing 2–4× with identical stats. Root cause: data/packages.json carried 250 duplicate package names (5500 rows, 5250 unique).

The npm search API paginates with from/size=250, and its total drifts between page requests (packages published/unpublished mid-enumeration). When total shifts, the same package lands on two adjacent pages. enumeratePackages collected every object without deduping by name → duplicates flowed into the committed packages.json and onto the live site. CI is vulnerable every cron run because its data/.cache/ is gitignored + ephemeral.

Fix (3 layers)

  1. pipeline/npm.ts — dedup at the source. enumeratePackages tracks a Set<string> of seen names and skips duplicates as pages arrive.
  2. pipeline/normalize.ts — defensive dedup in buildIndex. Keeps first occurrence by name, so a stale search cache predating the fix can never produce duplicate rows either.
  3. data/packages.json + packages.min.json — corrected in place. Dropped the 250 duplicate rows immediately so the live site is clean on the next deploy instead of waiting for the 04:00 UTC cron.

Tests

Added pipeline/normalize.test.ts (node:test via tsx, no new deps) + wired pnpm test:run:

✔ buildIndex dedupes packages with the same name, keeping the first
✔ buildIndex count matches packages length for an already-unique list
ℹ pass 2 · fail 0

Every consumer reads the now-deduped source: SSG pages (src/lib/data.ts), /api/packages route (getIndex()), and public/data/*.json (scripts/copy-data.mjs prebuild).

Commits split: code+tests, then corrective data dedup.

rz1989s added 2 commits July 23, 2026 16:25
The npm search API's `total` drifts between page requests (packages are
published/unpublished mid-enumeration), so the same package can land on two
adjacent pages. enumeratePackages collected every object without deduping by
name, producing duplicate rows in the published index (~250 dups in the Jul
14 run).

- enumeratePackages: track seen names in a Set, skip duplicates at the source
- buildIndex: defensive dedup by name (keeps first occurrence) so a stale
  search cache predating the fix can never produce duplicate rows either
- add pipeline/normalize.test.ts (node:test via tsx) covering both dedup paths
- wire `pnpm test:run`
Corrective dedup of the committed index so the live site serves clean data
on the next deploy instead of waiting for the 04:00 UTC cron to regenerate
from scratch. No API access needed — pure row dedup (keeps first occurrence).

Generated by the same dedup logic now in buildIndex; count field realigned to
5250. The next pipeline cron will refresh from npm with the pagination fix.
@vercel

vercel Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
pi-package-index Ready Ready Preview, Comment Jul 23, 2026 9:30am

Resolve data/packages.json + .min.json conflict by taking origin/main's
latest CI-generated data (6000 rows, 750 dups — root cause still unfixed on
main) and applying the same dedup: 6000 -> 5250. readmes.json merged cleanly.
@rz1989s
rz1989s merged commit 487a888 into main Jul 23, 2026
3 checks passed
@rz1989s
rz1989s deleted the fix/pipeline-dedupe-npm-pagination branch July 23, 2026 09:32
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.

1 participant