mirror of
https://github.com/openclaw/clawhub.git
synced 2026-08-14 00:47:57 +00:00
fix: require six times P99 for sustained signals (#3204)
This commit is contained in:
@@ -449,24 +449,27 @@ describe("publisher abuse scoring", () => {
|
||||
expect(score.reasonCodes).toContain("temporal_download_spike_flat_installs");
|
||||
});
|
||||
|
||||
it("flags sustained high downloads with flat installs", () => {
|
||||
it("flags sustained flat-install traffic one download above six times platform P99", () => {
|
||||
const todayDay = 100;
|
||||
const score = computeCurrentSkillTemporalAbuseScore({
|
||||
todayDay,
|
||||
benchmark: temporalBenchmark({
|
||||
downloads30dP95: 3_000,
|
||||
downloads30dP99: 3_000,
|
||||
downloads30dP95: 284,
|
||||
downloads30dP99: 600,
|
||||
spikeMultiplier7dP95: 20,
|
||||
spikeMultiplier7dP99: 50,
|
||||
}),
|
||||
dailyStats: dailyRange(71, 30, { downloads: 120, installs: 0 }),
|
||||
dailyStats: [
|
||||
...dailyRange(71, 29, { downloads: 120, installs: 0 }),
|
||||
{ day: 100, downloads: 121, installs: 0 },
|
||||
],
|
||||
});
|
||||
|
||||
expect(score.spike).toBe(false);
|
||||
expect(score.sustained).toBe(true);
|
||||
expect(score.recent30Downloads).toBe(3_600);
|
||||
expect(score.recent30Downloads).toBe(3_601);
|
||||
expect(score.recent30Installs).toBe(0);
|
||||
expect(score.downloadInstallRatio30).toBe(3_600);
|
||||
expect(score.downloadInstallRatio30).toBe(3_601);
|
||||
expect(score.downloads30dCohortBand).toBe("p99");
|
||||
expect(score.reasonCodes).toContain("temporal_sustained_downloads_flat_installs");
|
||||
});
|
||||
@@ -486,17 +489,17 @@ describe("publisher abuse scoring", () => {
|
||||
expect(score.downloads30dCohortBand).toBeUndefined();
|
||||
});
|
||||
|
||||
it("keeps sub-3000 P99 download traffic below the absolute review floor", () => {
|
||||
it("keeps downloads at exactly six times platform P99 below the sustained threshold", () => {
|
||||
const score = computeCurrentSkillTemporalAbuseScore({
|
||||
todayDay: 100,
|
||||
benchmark: temporalBenchmark({
|
||||
downloads30dP95: 1_000,
|
||||
downloads30dP99: 2_000,
|
||||
downloads30dP95: 284,
|
||||
downloads30dP99: 600,
|
||||
}),
|
||||
dailyStats: dailyRange(71, 30, { downloads: 90, installs: 0 }),
|
||||
dailyStats: dailyRange(71, 30, { downloads: 120, installs: 0 }),
|
||||
});
|
||||
|
||||
expect(score.recent30Downloads).toBe(2_700);
|
||||
expect(score.recent30Downloads).toBe(3_600);
|
||||
expect(score.sustained).toBe(false);
|
||||
expect(score.downloads30dCohortBand).toBeUndefined();
|
||||
});
|
||||
@@ -611,8 +614,8 @@ describe("publisher abuse scoring", () => {
|
||||
it("finds historical spike and sustained windows for backfill scans", () => {
|
||||
const score = computeHistoricalSkillTemporalAbuseScore({
|
||||
benchmark: temporalBenchmark({
|
||||
downloads30dP95: 3_000,
|
||||
downloads30dP99: 10_000,
|
||||
downloads30dP95: 284,
|
||||
downloads30dP99: 1_000,
|
||||
spikeMultiplier7dP95: 5,
|
||||
spikeMultiplier7dP99: 25,
|
||||
}),
|
||||
|
||||
@@ -128,7 +128,7 @@ const TEMPORAL_SUSTAINED_DAYS = 30;
|
||||
const TEMPORAL_MAX_SPIKE_INSTALLS = 2;
|
||||
const TEMPORAL_MAX_SUSTAINED_INSTALLS = 5;
|
||||
const TEMPORAL_MIN_SPIKE_7_DOWNLOADS = 2_000;
|
||||
const TEMPORAL_MIN_SUSTAINED_30_DOWNLOADS = 3_000;
|
||||
const TEMPORAL_SUSTAINED_DOWNLOADS_P99_MULTIPLIER = 6;
|
||||
const TEMPORAL_MIN_BASELINE_7_DOWNLOADS = 100;
|
||||
const TEMPORAL_MIN_NEAR_CONVERSION_7_DOWNLOADS = 500;
|
||||
const TEMPORAL_MIN_NEAR_CONVERSION_30_DOWNLOADS = 1_000;
|
||||
@@ -437,7 +437,8 @@ export function classifySkillTemporalAbuseScore(
|
||||
score.spikeMultiplier / Math.max(1, benchmark.spikeMultiplier7dP95);
|
||||
const downloads30dCohortBand =
|
||||
score.recent30Installs <= TEMPORAL_MAX_SUSTAINED_INSTALLS &&
|
||||
score.recent30Downloads >= TEMPORAL_MIN_SUSTAINED_30_DOWNLOADS
|
||||
score.recent30Downloads >
|
||||
benchmark.downloads30dP99 * TEMPORAL_SUSTAINED_DOWNLOADS_P99_MULTIPLIER
|
||||
? p99Band({ value: score.recent30Downloads, p99: benchmark.downloads30dP99 })
|
||||
: undefined;
|
||||
const spikeMultiplierCohortBand =
|
||||
|
||||
@@ -655,8 +655,8 @@ describe("scheduled temporal publisher abuse scan", () => {
|
||||
sampleSize: 1_000,
|
||||
downloads30dAverage: 180,
|
||||
downloads30dMedian: 45,
|
||||
downloads30dP95: 900,
|
||||
downloads30dP99: 3_000,
|
||||
downloads30dP95: 284,
|
||||
downloads30dP99: 600,
|
||||
spikeMultiplier7dP95: 4,
|
||||
spikeMultiplier7dP99: 12,
|
||||
};
|
||||
@@ -667,7 +667,7 @@ describe("scheduled temporal publisher abuse scan", () => {
|
||||
});
|
||||
const candidate = temporalCandidate(
|
||||
"skills:anysearch" as Id<"skills">,
|
||||
temporalScore({ recent30Downloads: 3_370, recent30Installs: 4 }),
|
||||
temporalScore({ recent30Downloads: 3_700, recent30Installs: 4 }),
|
||||
);
|
||||
const runQuery = vi
|
||||
.fn()
|
||||
|
||||
@@ -94,10 +94,10 @@ See also: [acceptable-usage.md](./acceptable-usage.md) for the marketplace polic
|
||||
Partial scans must not archive signals or present their top-download slice as
|
||||
a platform percentile.
|
||||
- Flat-install temporal review signals are deliberately high-confidence:
|
||||
sustained volume must exceed the platform P99, reach at least 3,000 downloads
|
||||
in 30 days, and have at most 5 installs; a spike must exceed the platform P99,
|
||||
reach at least 2,000 downloads in 7 days, and have at most 2 installs. These
|
||||
signals indicate anomalous traffic for manual review, not publisher attribution.
|
||||
sustained volume must exceed six times the platform 30-day download P99 and
|
||||
have at most 5 installs; a spike must exceed the platform P99, reach at least
|
||||
2,000 downloads in 7 days, and have at most 2 installs. These signals indicate
|
||||
anomalous traffic for manual review, not publisher attribution.
|
||||
- Publisher abuse scoring must skip staff-linked and official publishers before
|
||||
nominations are created. Publisher abuse autoban must process pending
|
||||
`potential_ban_candidate` pressure nominations without waiting for the score
|
||||
|
||||
Reference in New Issue
Block a user