Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions scripts/ad-networks/niche-sort.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ export function validateNicheBatch(input, output) {
if (seen.has(row.domain)) throw new Error(`Duplicate result: ${row.domain}`);
seen.add(row.domain); rows.push(row);
}
if (seen.size !== domains.size) throw new Error(`Domain set mismatch: expected ${domains.size}, received ${seen.size}`);
// The model sometimes drops a site from a long batch. Keep the answers it gave: a missing site
// isn't checkpointed, so the next run asks again. An empty answer is still a failed call.
if (!seen.size) throw new Error(`No niche results for a batch of ${domains.size}`);
return rows;
}

Expand Down Expand Up @@ -145,7 +147,7 @@ export async function sortNiches(options, dependencies = {}) {
}
// Also retry revalidation when a previous run committed before it failed.
await (dependencies.revalidate ?? revalidateAdNetworks)(options);
return { applied: true, environment: options.environment, classified: input.length, imported, withheld, synced: true, revalidated: true };
return { applied: true, environment: options.environment, classified, imported, withheld, synced: true, revalidated: true };
} catch (error) {
error.jobResult = { classified, imported, withheld, synced: imported > 0, revalidated: false }; throw error;
} finally {
Expand Down
7 changes: 5 additions & 2 deletions tests/pages/ad-networks/niche-sort.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@ import { adNetworkNicheShares, hasAdNetworkNicheCoverage } from '../../../lib/ad
const input = [{ domain: 'example.com' }, { domain: 'example.org' }];
const result = (domain, niche = 'food', confidence = 'high') => ({ domain, niche, confidence });
const lines = rows => rows.map(row => JSON.stringify(row)).join('\n');
test('model validation requires the exact input set once each, known labels, and confidence', () => {
test('model validation takes only input domains once each, with known labels and confidence', () => {
const correct = [result('example.com'), result('example.org', null, 'low')];
assert.deepEqual(validateNicheBatch(input, lines(correct)), correct);
for (const bad of [[correct[0]], [correct[0], correct[0]], [...correct, result('extra.com')],
// A dropped site is left for the next run; an empty answer fails.
assert.deepEqual(validateNicheBatch(input, lines([correct[0]])), [correct[0]]);
assert.throws(() => validateNicheBatch(input, ''), /No niche results/);
for (const bad of [[correct[0], correct[0]], [...correct, result('extra.com')],
[result('example.com', 'invented'), correct[1]], [result('example.com', 'food', 1.5), correct[1]],
[{ ...correct[0], comment: 'extra' }, correct[1]], [result('https://example.com'), correct[1]]]) {
assert.throws(() => validateNicheBatch(input, lines(bad)));
Expand Down
Loading