Docs/Skills and code/src/

src/analysis/qualification-scope.js

Code89 lines3.8 KBsrc/

import { config } from "../../config.js";

const args = new Set(process.argv.slice(2));
const forceAll = args.has("--include-irrelevant");
const forceChannels = forceAll || args.has("--include-irrelevant-channels");
const forceVideos = forceAll || args.has("--include-irrelevant-videos");
const channelCache = new Map();
const videoChannelCache = new Map();

function tableExists(db, name) {
  return Boolean(db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name=?").get(name));
}

/**
 * True only for a confidently irrelevant channel in the latest successful LLM
 * qualification for the active prompt version. Unknown, stale, failed, low-confidence,
 * or not-yet-qualified channels remain eligible.
 */
export function isIrrelevantChannel(db, channelUrl) {
  if (!channelUrl) return false;
  if (channelCache.has(channelUrl)) return channelCache.get(channelUrl);
  let irrelevant = false;
  if (tableExists(db, "channel_qualification_llm_results")) {
    const result = db.prepare(`
      SELECT classification, confidence
      FROM channel_qualification_llm_results
      WHERE channel_url=? AND processing_status='succeeded' AND prompt_version=?
      ORDER BY created_at DESC LIMIT 1
    `).get(channelUrl, config.qualification.promptVersion);
    const threshold = Number(config.qualification.minimumConfidenceToQualify ?? 0.58);
    irrelevant = result?.classification === "irrelevant" && Number(result.confidence) >= threshold;
  }
  channelCache.set(channelUrl, irrelevant);
  return irrelevant;
}

function videoChannelUrls(db, videoId) {
  if (!videoId) return [];
  if (videoChannelCache.has(videoId)) return videoChannelCache.get(videoId);
  const urls = new Set();
  if (tableExists(db, "videos")) {
    const row = db.prepare("SELECT channel_url FROM videos WHERE video_id=?").get(videoId);
    if (row?.channel_url) urls.add(row.channel_url);
  }
  if (tableExists(db, "channel_videos")) {
    for (const row of db.prepare("SELECT DISTINCT channel_url FROM channel_videos WHERE video_id=?").all(videoId)) {
      if (row.channel_url) urls.add(row.channel_url);
    }
  }
  const result = [...urls];
  videoChannelCache.set(videoId, result);
  return result;
}

/**
 * Filter a selected array in memory, preserving all canonical database records.
 * kind='channel' filters channel rows; kind='video' filters video rows by all known
 * channel relationships. Rows without enough relationship evidence are retained.
 */
export function filterQualifiedRows(db, rows, kind = "mixed", { label = "stage" } = {}) {
  if (!Array.isArray(rows) || rows.length === 0) return rows ?? [];
  if ((kind === "channel" && forceChannels) || (kind === "video" && forceVideos) || forceAll) {
    console.log(`[qualification-scope] ${label}: forced inclusion enabled for ${kind} rows; ${rows.length} rows retained`);
    return rows;
  }
  const before = rows.length;
  const kept = rows.filter(row => {
    if (kind === "channel") {
      return !isIrrelevantChannel(db, row.channel_url ?? row.channelUrl);
    }
    if (kind === "video") {
      const urls = videoChannelUrls(db, row.video_id ?? row.videoId);
      // Keep orphan/unlinked videos and videos linked to at least one eligible channel.
      return urls.length === 0 || urls.some(url => !isIrrelevantChannel(db, url));
    }
    const directUrl = row.channel_url ?? row.channelUrl;
    if (directUrl && isIrrelevantChannel(db, directUrl)) return false;
    const videoId = row.video_id ?? row.videoId;
    if (videoId) {
      const urls = videoChannelUrls(db, videoId);
      if (urls.length > 0 && urls.every(url => isIrrelevantChannel(db, url))) return false;
    }
    return true;
  });
  const removed = before - kept.length;
  console.log(`[qualification-scope] ${label}: retained=${kept.length} ignored_irrelevant=${removed} kind=${kind}`);
  return kept;
}

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.