fix: refresh Trending download snapshots (#3355)

This commit is contained in:
Patrick Erichsen
2026-07-31 09:58:38 -07:00
committed by GitHub
parent 476feb2af1
commit a9b4494807
4 changed files with 77 additions and 9 deletions
+73 -6
View File
@@ -215,7 +215,7 @@ describe("canonical Trending snapshot storage", () => {
snapshotId: "skills-1000",
generatedAt: new Date(now - 1_000).toISOString(),
windowHours: 24,
rankingVersion: "skills-trending-v2",
rankingVersion: "skills-trending-v3",
items: [
{ id: "clawhub:one", rank: 1, lane: "clawhub-trending" },
{ id: "clawhub:two", rank: 2, lane: "clawhub-trending" },
@@ -556,6 +556,7 @@ describe("canonical Trending snapshot storage", () => {
it("returns the current native-only snapshot for guarded preflight reuse", async () => {
const t = convexTest(schema, modules);
const now = Date.now();
const source = await insertEligibleNativeSource(t, "native-preflight-ready");
await t.mutation(internal.canonicalTrending.startSnapshotInternal, {
snapshotId: "skills-native-preflight-ready",
generatedAt: now - 1_000,
@@ -563,11 +564,28 @@ describe("canonical Trending snapshot storage", () => {
windowStartDay: 40,
windowEndDay: 40,
});
await t.mutation(internal.canonicalTrending.writeItemsInternal, {
snapshotId: "skills-native-preflight-ready",
items: [
{
position: 0,
lane: "clawhub-trending",
sourceRef: { kind: "clawhub", skillId: source.skillId },
card: {
...nativeCard("clawhub:native-preflight-ready", 8),
metrics: {
...nativeCard("clawhub:native-preflight-ready", 8).metrics,
trending24hDownloads: 6,
},
},
},
],
});
await t.mutation(internal.canonicalTrending.finalizeSnapshotInternal, {
snapshotId: "skills-native-preflight-ready",
completedAt: now - 500,
totalItems: 0,
sourceCounts: { clawhubTrending: 3, clawhubRising: 2, skillsShTrending: 0 },
totalItems: 1,
sourceCounts: { clawhubTrending: 1, clawhubRising: 0, skillsShTrending: 0 },
operations: { documentsRead: 10, documentsWritten: 2, functionCalls: 3 },
});
@@ -578,14 +596,63 @@ describe("canonical Trending snapshot storage", () => {
snapshotId: "skills-native-preflight-ready",
generatedAt: new Date(now - 1_000).toISOString(),
windowHours: 24,
rankingVersion: "skills-trending-v2",
totalItems: 0,
sourceCounts: { clawhubTrending: 3, clawhubRising: 2, skillsShTrending: 0 },
rankingVersion: "skills-trending-v3",
totalItems: 1,
sourceCounts: { clawhubTrending: 1, clawhubRising: 0, skillsShTrending: 0 },
operations: { documentsRead: 10, documentsWritten: 2, functionCalls: 3 },
reused: true,
});
});
it("does not reuse a native-only snapshot from the pre-download ranking version", async () => {
const t = convexTest(schema, modules);
const now = Date.now();
const source = await insertEligibleNativeSource(t, "legacy-native-preflight");
await t.mutation(internal.canonicalTrending.startSnapshotInternal, {
snapshotId: "skills-legacy-native-preflight",
generatedAt: now - 1_000,
expiresAt: now + 24 * 60 * 60 * 1_000,
windowStartDay: 40,
windowEndDay: 40,
});
await t.mutation(internal.canonicalTrending.writeItemsInternal, {
snapshotId: "skills-legacy-native-preflight",
items: [
{
position: 0,
lane: "clawhub-trending",
sourceRef: { kind: "clawhub", skillId: source.skillId },
card: {
...nativeCard("clawhub:legacy-native-preflight", 8),
metrics: {
...nativeCard("clawhub:legacy-native-preflight", 8).metrics,
trending24hDownloads: 6,
},
},
},
],
});
await t.mutation(internal.canonicalTrending.finalizeSnapshotInternal, {
snapshotId: "skills-legacy-native-preflight",
completedAt: now - 500,
totalItems: 1,
sourceCounts: { clawhubTrending: 1, clawhubRising: 0, skillsShTrending: 0 },
operations: { documentsRead: 10, documentsWritten: 2, functionCalls: 3 },
});
await t.run(async (ctx) => {
const snapshot = await ctx.db
.query("canonicalTrendingSnapshots")
.withIndex("by_snapshot_id", (q) => q.eq("snapshotId", "skills-legacy-native-preflight"))
.unique();
if (!snapshot) throw new Error("Expected legacy native snapshot");
await ctx.db.patch(snapshot._id, { rankingVersion: "skills-trending-v2" });
});
await expect(
t.query(internal.canonicalTrending.getReadyNativeSnapshotInternal, { now }),
).resolves.toBeNull();
});
it("never serves a snapshot produced by the legacy ranking algorithm", async () => {
const t = convexTest(schema, modules);
const now = Date.now();
+1 -1
View File
@@ -122,7 +122,7 @@ describe("CLAW-590 permanent Test snapshot ownership", () => {
snapshotId: SNAPSHOT_ID,
kind: "skills",
status: "failed",
rankingVersion: "skills-trending-v2",
rankingVersion: "skills-trending-v3",
generatedAt: 1_000,
completedAt: 2_000,
expiresAt: Date.now() + 100_000,
+2 -1
View File
@@ -7,6 +7,7 @@ import {
internalQuery,
type QueryCtx,
} from "./_generated/server";
import { CANONICAL_TRENDING_RANKING_VERSION } from "./lib/canonicalTrending";
import { getCompletedRolling24HourWindow } from "./lib/skillHourlyStats";
import { assertTestSeedAllowed } from "./lib/testSeed";
@@ -311,7 +312,7 @@ function assertOwnedSnapshot(snapshot: Doc<"canonicalTrendingSnapshots">, snapsh
if (
snapshot.snapshotId !== snapshotId ||
snapshot.kind !== "skills" ||
snapshot.rankingVersion !== "skills-trending-v2" ||
snapshot.rankingVersion !== CANONICAL_TRENDING_RANKING_VERSION ||
snapshot.windowHours !== 24
) {
throw new Error("CLAW-590 proof snapshot ownership mismatch");
+1 -1
View File
@@ -1,7 +1,7 @@
import { type Infer, v } from "convex/values";
import type { Doc } from "../_generated/dataModel";
export const CANONICAL_TRENDING_RANKING_VERSION = "skills-trending-v2";
export const CANONICAL_TRENDING_RANKING_VERSION = "skills-trending-v3";
export const CANONICAL_TRENDING_WINDOW_HOURS = 24;
export const CANONICAL_TRENDING_FIRST_PAGE_SIZE = 20;
export const CANONICAL_TRENDING_PUBLISHER_CAP = 2;