Skip to content

Commit e90a2b2

Browse files
committed
fix: stop metadata lane overwriting 30d download mirror
Signed-off-by: anilb <epipav@gmail.com>
1 parent 6c0c214 commit e90a2b2

7 files changed

Lines changed: 15 additions & 17 deletions

File tree

services/apps/packages_worker/src/packagist/__tests__/dueSelection.test.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,6 @@ describe('updatePackagistPackageStats', () => {
207207
declaredRepositoryUrl: null,
208208
repositoryUrl: null,
209209
status: 'active',
210-
downloadsLast30d: 1,
211210
totalDownloads: 2,
212211
dependentCount: 3,
213212
}),
@@ -229,7 +228,6 @@ describe('updatePackagistPackageStats', () => {
229228
declaredRepositoryUrl: 'https://github.com/a/x',
230229
repositoryUrl: 'https://github.com/a/x',
231230
status: 'active',
232-
downloadsLast30d: 1,
233231
totalDownloads: 2,
234232
dependentCount: 3,
235233
})

services/apps/packages_worker/src/packagist/__tests__/normalize.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ describe('normalizePackagistStats', () => {
3333
downloads: { total: 500_000_000, monthly: 10_000_000, daily: 350_000 },
3434
}
3535

36-
it('extracts description, repository, dependents and the three download counters', () => {
36+
it('extracts description, repository, dependents and total downloads', () => {
3737
const stats = normalizePackagistStats(full)
3838
expect(stats).toEqual({
3939
name: 'monolog/monolog',
@@ -42,7 +42,8 @@ describe('normalizePackagistStats', () => {
4242
status: 'active',
4343
dependents: 5423,
4444
downloadsTotal: 500_000_000,
45-
downloadsMonthly: 10_000_000,
45+
// downloads.monthly is deliberately not extracted — packages.downloads_last_30d
46+
// belongs exclusively to the dedicated downloads-30d lane
4647
// nameless maintainer entries are dropped
4748
maintainers: [{ username: 'seldaek', displayName: null, email: null, role: 'maintainer' }],
4849
})
@@ -76,7 +77,6 @@ describe('normalizePackagistStats', () => {
7677
status: 'active',
7778
dependents: null,
7879
downloadsTotal: null,
79-
downloadsMonthly: null,
8080
maintainers: [],
8181
})
8282
})

services/apps/packages_worker/src/packagist/__tests__/persistPackageInfo.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ const stats: NormalizedPackagistStats = {
4141
status: 'active',
4242
dependents: 42,
4343
downloadsTotal: 1000,
44-
downloadsMonthly: 300,
4544
maintainers: [{ username: 'seldaek', displayName: null, email: null, role: 'maintainer' }],
4645
}
4746

@@ -70,11 +69,13 @@ describe('persistPackagistPackageInfo', () => {
7069
purl: PURL,
7170
description: 'logs',
7271
status: 'active',
73-
downloadsLast30d: 300,
7472
totalDownloads: 1000,
7573
dependentCount: 42,
7674
}),
7775
)
76+
// packages.downloads_last_30d belongs exclusively to the dedicated downloads-30d
77+
// lane's boundary-anchored snapshot — the metadata lane must never touch it
78+
expect(mockUpdate.mock.calls[0][1]).not.toHaveProperty('downloadsLast30d')
7879
// canonicalized (lowercased) url + coarse host, linked with the manifest-declared convention
7980
expect(mockRepoGet).toHaveBeenCalledWith(qx, 'https://github.com/seldaek/monolog', 'github')
8081
expect(mockRepoLink).toHaveBeenCalledWith(qx, '7', '55', 'declared', 0.8)

services/apps/packages_worker/src/packagist/normalize.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,10 @@ export function normalizePackagistStats(pkg: PackagistPackageInfo): NormalizedPa
2828
status = 'deprecated'
2929
}
3030

31-
// Extract downloads, defaulting to null if not a number
31+
// Extract downloads, defaulting to null if not a number. downloads.monthly is
32+
// deliberately not extracted here — packages.downloads_last_30d belongs exclusively
33+
// to the dedicated downloads-30d lane's boundary-anchored snapshot.
3234
const downloadsTotal = typeof pkg.downloads?.total === 'number' ? pkg.downloads.total : null
33-
const downloadsMonthly = typeof pkg.downloads?.monthly === 'number' ? pkg.downloads.monthly : null
3435

3536
const dependents = typeof pkg.dependents === 'number' ? pkg.dependents : null
3637

@@ -55,7 +56,6 @@ export function normalizePackagistStats(pkg: PackagistPackageInfo): NormalizedPa
5556
status,
5657
dependents,
5758
downloadsTotal,
58-
downloadsMonthly,
5959
maintainers,
6060
}
6161
}

services/apps/packages_worker/src/packagist/types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ export interface NormalizedPackagistStats {
6666
status: 'active' | 'deprecated'
6767
dependents: number | null
6868
downloadsTotal: number | null
69-
downloadsMonthly: number | null
7069
maintainers: PackageMaintainerInput[]
7170
}
7271

services/apps/packages_worker/src/packagist/upsertPackageInfo.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ export async function persistPackagistPackageInfo(
5050
declaredRepositoryUrl: stats.repositoryUrl,
5151
repositoryUrl: trustedRepo?.url ?? null,
5252
status: stats.status,
53-
downloadsLast30d: stats.downloadsMonthly,
5453
totalDownloads: stats.downloadsTotal,
5554
dependentCount: stats.dependents,
5655
})

services/libs/data-access-layer/src/packages/packages.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -259,11 +259,14 @@ export interface PackagistStatsUpdateInput {
259259
declaredRepositoryUrl: string | null
260260
repositoryUrl: string | null
261261
status: string
262-
downloadsLast30d: number | null
263262
totalDownloads: number | null
264263
dependentCount: number | null
265264
}
266265

266+
// downloads_last_30d is NOT written here — it belongs exclusively to the dedicated
267+
// downloads-30d lane's boundary-anchored, insert-if-absent snapshot. The metadata
268+
// lane's live rolling `downloads.monthly` value is a different, unanchored reading;
269+
// writing it here would silently overwrite that snapshot every weekly refresh.
267270
export async function updatePackagistPackageStats(
268271
qx: QueryExecutor,
269272
input: PackagistStatsUpdateInput,
@@ -272,7 +275,7 @@ export async function updatePackagistPackageStats(
272275
await qx.selectOneOrNone(
273276
`WITH old AS (
274277
SELECT description, declared_repository_url, repository_url, status,
275-
downloads_last_30d, total_downloads, dependent_count, ingestion_source
278+
total_downloads, dependent_count, ingestion_source
276279
FROM packages WHERE purl = $(purl) AND ecosystem = 'packagist'
277280
),
278281
ins AS (
@@ -281,21 +284,19 @@ export async function updatePackagistPackageStats(
281284
declared_repository_url = $(declaredRepositoryUrl),
282285
repository_url = $(repositoryUrl),
283286
status = $(status),
284-
downloads_last_30d = COALESCE($(downloadsLast30d), downloads_last_30d),
285287
total_downloads = COALESCE($(totalDownloads), total_downloads),
286288
dependent_count = COALESCE($(dependentCount), dependent_count),
287289
last_synced_at = NOW()
288290
WHERE purl = $(purl) AND ecosystem = 'packagist'
289291
RETURNING id, is_critical, description, declared_repository_url, repository_url, status,
290-
downloads_last_30d, total_downloads, dependent_count, ingestion_source
292+
total_downloads, dependent_count, ingestion_source
291293
)
292294
SELECT ins.id::text AS id, ins.is_critical,
293295
array_remove(ARRAY[
294296
CASE WHEN o.description IS DISTINCT FROM ins.description THEN 'packages.description' END,
295297
CASE WHEN o.declared_repository_url IS DISTINCT FROM ins.declared_repository_url THEN 'packages.declared_repository_url' END,
296298
CASE WHEN o.repository_url IS DISTINCT FROM ins.repository_url THEN 'packages.repository_url' END,
297299
CASE WHEN o.status IS DISTINCT FROM ins.status THEN 'packages.status' END,
298-
CASE WHEN o.downloads_last_30d IS DISTINCT FROM ins.downloads_last_30d THEN 'packages.downloads_last_30d' END,
299300
CASE WHEN o.total_downloads IS DISTINCT FROM ins.total_downloads THEN 'packages.total_downloads' END,
300301
CASE WHEN o.dependent_count IS DISTINCT FROM ins.dependent_count THEN 'packages.dependent_count' END,
301302
CASE WHEN o.ingestion_source IS DISTINCT FROM ins.ingestion_source THEN 'packages.ingestion_source' END

0 commit comments

Comments
 (0)