Docs/Skills and code/tests/
tests/series-analysis.test.js
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import { buildQueries } from "../src/series-analysis/queries.js";
import { failureHits, guessSubject, nonReplicableFlags, percentileRank, structureMatches } from "../src/series-analysis/signals.js";
import { durationScore, outlierScore, scoreCandidates, scoreFit, selectLearnFrom, sizeScore } from "../src/series-analysis/scoring.js";
const spec = JSON.parse(fs.readFileSync(new URL("../series/why-x-died.json", import.meta.url), "utf8"));
const NOW = Date.parse("2026-10-20T00:00:00Z");
const daysAgo = d => new Date(NOW - d * 86400000).toISOString();
test("query plan covers every tier, has no duplicates and respects the budget", () => {
const qs = buildQueries(spec, 60);
assert.equal(qs.length, 60);
assert.equal(new Set(qs.map(q => q.query.toLowerCase())).size, 60);
for (const tier of ["exact", "exact-hinglish", "adjacent-packaging", "generic", "adjacent-topic", "reference-channel"]) {
assert.ok(qs.some(q => q.tier === tier), `missing tier ${tier}`);
}
assert.ok(qs.filter(q => q.tier === "exact").every(q => /Died|Fall|Happened|Collapse|Downfall/.test(q.query)));
});
test("small budget still spreads across companies instead of exhausting one formula", () => {
const exact = buildQueries(spec, 30).filter(q => q.tier === "exact");
assert.ok(new Set(exact.map(q => q.anchor)).size === exact.length);
assert.ok(new Set(exact.map(q => q.formula)).size > 1);
});
test("title signals", () => {
assert.deepEqual(structureMatches("Why Kingfisher Airlines Died | Business Case Study").slice(0, 1), ["why-how-X-died"]);
assert.ok(failureHits("The Painful Downfall of Big Bazaar", spec.failureTerms).includes("downfall"));
assert.equal(failureHits("Best crochet tutorial", spec.failureTerms).length, 0);
assert.ok(nonReplicableFlags("Vijay Mallya Podcast: Rise & Downfall Of Kingfisher | Raj Shamani").includes("podcast/interview"));
assert.equal(guessSubject("How Ego Killed Kingfisher Airlines", [...spec.companies.indian]).key, "kingfisher");
assert.equal(guessSubject("Why Quibi Died", spec.companies.indian).key, "quibi");
});
test("fit separates on-series titles from noise", () => {
const f = t => scoreFit({ title: t, query_hits: 2 }, spec).fit;
assert.ok(f("Why Jet Airways Died | Business Case Study") > 0.7);
assert.ok(f("Easy Crochet Tutorial for Beginners") < 0.3);
assert.ok(f("Why Jet Airways Died") > f("Jet Airways Business Class Review"));
});
test("component scores behave", () => {
assert.equal(durationScore(15 * 60, [8, 35]), 1);
assert.ok(durationScore(45, [8, 35]) < 0.1);
assert.equal(sizeScore(100000, [10000, 1500000]), 1);
assert.ok(sizeScore(30e6, [10000, 1500000]) < sizeScore(100000, [10000, 1500000]));
assert.ok(outlierScore(10) > outlierScore(3) && outlierScore(3) > outlierScore(1));
assert.equal(outlierScore(null), null);
assert.equal(percentileRank([1, 2, 3, 4], 5), 1);
});
const vid = (id, title, o = {}) => ({
video_id: id, title, channel_key: o.ch ?? `ch-${id}`, channel_name: o.ch ?? `ch-${id}`, views: 100000, likes: 3000,
published_at: daysAgo(400), duration_seconds: 900, query_hits: 2, ...o
});
test("a breakout on a small channel outranks a bigger absolute number on a giant channel", () => {
const videos = [
vid("a", "Why Dunzo Died", { ch: "small", views: 400000 }),
vid("b", "Why Nokia Died", { ch: "giant", views: 2000000 }),
vid("c", "Why Koo Died", { ch: "mid", views: 90000 }),
vid("d", "Why Byju's Failed", { ch: "mid2", views: 50000 })
];
const channels = new Map([
["small", { subscriber_count: 80000, baseline_median_views: 40000, baseline_n: 30 }],
["giant", { subscriber_count: 20e6, baseline_median_views: 3000000, baseline_n: 30 }],
["mid", { subscriber_count: 300000, baseline_median_views: 80000, baseline_n: 30 }],
["mid2", { subscriber_count: 300000, baseline_median_views: 80000, baseline_n: 30 }]
]);
const scored = scoreCandidates(videos, channels, spec, { now: NOW });
const by = Object.fromEntries(scored.map(r => [r.video_id, r]));
assert.ok(by.a.learn_score > by.b.learn_score);
assert.ok(by.a.learn_score > by.d.learn_score);
assert.equal(by.a.tier, "series-exact");
});
test("podcasts and off-series titles do not make the learn-from set", () => {
const videos = [
vid("p", "Why Kingfisher Airlines Died | Vijay Mallya Podcast", { views: 30000000 }),
vid("x", "Crochet blanket tutorial", { views: 5000000 }),
vid("g", "Why Jet Airways Died", { views: 300000 })
];
const scored = scoreCandidates(videos, new Map(), spec, { now: NOW });
assert.equal(scored.find(r => r.video_id === "x").learn_score, null);
const picked = selectLearnFrom(scored, spec, { topN: 3 }).map(r => r.video_id);
assert.equal(picked[0], "g");
assert.ok(!picked.includes("x"));
});
test("selection caps picks per channel and per company", () => {
const videos = [
vid("1", "Why Kingfisher Airlines Died", { ch: "A", views: 900000 }),
vid("2", "How Kingfisher Airlines Collapsed", { ch: "B", views: 800000 }),
vid("3", "Kingfisher Airlines Downfall Explained", { ch: "C", views: 700000 }),
vid("4", "Why Jet Airways Died", { ch: "A", views: 600000 }),
vid("5", "Why Satyam Collapsed", { ch: "A", views: 500000 }),
vid("6", "Why Koo Died", { ch: "D", views: 400000 })
];
const scored = scoreCandidates(videos, new Map(), spec, { now: NOW });
const picked = selectLearnFrom(scored, spec, { topN: 6, perChannel: 2, perSubject: 2 });
assert.ok(picked.filter(r => r.channel_key === "A").length <= 2);
assert.ok(picked.filter(r => r.subject === "kingfisher").length <= 2);
});
test("subject guessing uses whole words and skips generic nouns", () => {
const known = spec.companies.indian;
assert.equal(guessSubject("The Painful Downfall of Big Bazaar", known).key, "bazaar");
assert.notEqual(guessSubject("Biggest Business Failures Ever", known).source, "known");
assert.equal(guessSubject("Why Café Coffee Day Failed", known).key, "cafe");
assert.notEqual(guessSubject("Why the World’s Largest Megaproject Collapsed", known).key, "worlds");
assert.equal(guessSubject("Why Go First Airline Shut Down", known).source === "known", false);
});
Shown as it is in the repository at build time (2026-11-03); the home directory appears as <home>. If this page and the file differ, the file is right. Back to the catalogue.