Docs/Skills and code/src/
src/channel-qualification.js
function normalizeText(value) {
return String(value || "")
.toLowerCase()
.replace(/\s+/g, " ")
.trim();
}
function matchesTerm(text, term) {
return normalizeText(text).includes(
normalizeText(term)
);
}
function collectMatches(text, terms) {
return terms.filter((term) =>
matchesTerm(text, term)
);
}
function classifyChannel(
channel,
popularVideos,
newestVideos,
ecosystem
) {
const metadataText = [
channel.name,
channel.description,
...(channel.keywords || [])
]
.filter(Boolean)
.join(" ");
const videoTexts = [
...popularVideos,
...newestVideos
]
.map((video) => video.title)
.filter(Boolean);
const positiveMetadata =
collectMatches(
metadataText,
ecosystem.includeTerms
);
const negativeMetadata =
collectMatches(
metadataText,
ecosystem.excludeTerms
);
const positiveVideos = [];
for (const title of videoTexts) {
const matches = collectMatches(
title,
ecosystem.includeTerms
);
for (const match of matches) {
if (!positiveVideos.includes(match)) {
positiveVideos.push(match);
}
}
}
const negativeVideos = [];
for (const title of videoTexts) {
const matches = collectMatches(
title,
ecosystem.excludeTerms
);
for (const match of matches) {
if (!negativeVideos.includes(match)) {
negativeVideos.push(match);
}
}
}
let score = 0;
score += positiveMetadata.length * 3;
score += positiveVideos.length;
score -= negativeMetadata.length * 4;
score -= negativeVideos.length;
let classification = "unknown";
const strongPositive =
positiveMetadata.length >= 2 ||
(
positiveMetadata.length >= 1 &&
positiveVideos.length >= 2
);
if (
strongPositive &&
score >= 3
) {
classification = "core";
} else if (score <= -3) {
classification = "irrelevant";
} else if (score !== 0) {
classification = "adjacent";
}
const evidence = [];
if (positiveMetadata.length) {
evidence.push(
`positive metadata: ${positiveMetadata.join(", ")}`
);
}
if (positiveVideos.length) {
evidence.push(
`positive video titles: ${positiveVideos.join(", ")}`
);
}
if (negativeMetadata.length) {
evidence.push(
`negative metadata: ${negativeMetadata.join(", ")}`
);
}
if (negativeVideos.length) {
evidence.push(
`negative video titles: ${negativeVideos.join(", ")}`
);
}
let reason =
"no strong ecosystem signal";
if (evidence.length) {
reason = evidence.join(" | ");
}
return {
classification,
score,
reason,
evidence: {
positiveMetadata,
positiveVideos,
negativeMetadata,
negativeVideos
}
};
}
function classifyVideos(
videos,
ecosystem
) {
return videos.map((video) => {
const title =
normalizeText(video.title);
const positiveMatches =
collectMatches(
title,
ecosystem.includeTerms
);
const negativeMatches =
collectMatches(
title,
ecosystem.excludeTerms
);
let score =
positiveMatches.length -
negativeMatches.length;
let classification =
"unknown";
if (
negativeMatches.length > 0 &&
positiveMatches.length === 0
) {
classification = "irrelevant";
} else if (score > 0) {
classification = "core";
} else if (score < 0) {
classification = "adjacent";
}
const evidence = [];
if (positiveMatches.length) {
evidence.push(
`positive title terms: ${positiveMatches.join(", ")}`
);
}
if (negativeMatches.length) {
evidence.push(
`negative title terms: ${negativeMatches.join(", ")}`
);
}
const reason =
evidence.length
? evidence.join(" | ")
: "no strong ecosystem signal";
return {
...video,
classification,
score,
reason,
method: "rules"
};
});
}
function saveQualification(
db,
channelUrl,
ecosystem,
result
) {
const reviewedAt =
new Date().toISOString();
const updatedAt =
reviewedAt;
const ecosystemName =
typeof ecosystem === "string"
? ecosystem
: ecosystem?.name;
if (!ecosystemName) {
throw new Error(
"Cannot save qualification: ecosystem name is missing."
);
}
if (!result?.classification) {
throw new Error(
"Cannot save qualification: classification is missing."
);
}
const channelExists =
db.prepare(`
SELECT 1
FROM channels
WHERE channel_url = ?
`).get(channelUrl);
if (!channelExists) {
throw new Error(
`Cannot save qualification: channel does not exist in channels table: ${channelUrl}`
);
}
const statement = db.prepare(`
INSERT INTO channel_qualifications (
channel_url,
ecosystem,
classification,
score,
reason,
method,
reviewed_at,
updated_at
)
VALUES (
?, ?, ?, ?, ?, ?, ?, ?
)
ON CONFLICT(channel_url)
DO UPDATE SET
ecosystem = excluded.ecosystem,
classification = excluded.classification,
score = excluded.score,
reason = excluded.reason,
method = excluded.method,
reviewed_at = excluded.reviewed_at,
updated_at = excluded.updated_at
`);
const values = [
channelUrl,
ecosystemName,
result.classification,
result.score,
result.reason,
"rules",
reviewedAt,
updatedAt
];
console.log(
"[qualification] Saving channel qualification:",
{
channelUrl,
ecosystem: ecosystemName,
classification:
result.classification,
score:
result.score,
parameterCount:
values.length
}
);
statement.run(...values);
}
function saveVideoQualifications(
db,
videos,
ecosystem
) {
const ecosystemName =
typeof ecosystem === "string"
? ecosystem
: ecosystem?.name;
if (!ecosystemName) {
throw new Error(
"Cannot save video qualifications: ecosystem name is missing."
);
}
const statement = db.prepare(`
INSERT INTO video_qualifications (
video_id,
ecosystem,
classification,
score,
reason,
method,
reviewed_at,
updated_at
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(video_id)
DO UPDATE SET
ecosystem = excluded.ecosystem,
classification = excluded.classification,
score = excluded.score,
reason = excluded.reason,
method = excluded.method,
reviewed_at = excluded.reviewed_at,
updated_at = excluded.updated_at
`);
const now =
new Date().toISOString();
const transaction =
db.transaction(() => {
for (const video of videos) {
statement.run(
video.video_id,
ecosystemName,
video.classification,
video.score ?? 0,
video.reason,
video.method,
now,
now
);
}
});
transaction();
console.log(
`[qualification] Saved ${videos.length} video qualifications.`
);
}
export {
classifyChannel,
classifyVideos,
saveQualification,
saveVideoQualifications
};
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.