Docs/Skills and code/src/

src/analysis/channel-queues.js

Code416 lines38.6 KBsrc/

import { config } from "../../config.js";
import { buildSharedChannelEvidence, normalizeQualification } from "./channel-evidence.js";

export const QUEUES = [
  { key: "learn_from", label: "Best channels to learn from", purpose: "Ecosystem-relevant channels with a specific, inspectable editorial approach and repeatable evidence worth learning from." },
  { key: "breaking_out", label: "Static growth potential", purpose: "Ecosystem-relevant channels whose captured catalogue shows robust, repeatable performance relative to size; not a claim of current acceleration." },
  { key: "durable_exemplars", label: "Durable exemplars", purpose: "Ecosystem-relevant channels with a substantial body of work, longevity and repeated performance rather than scale alone." },
  { key: "unexplored_niches", label: "Unexplored niches", purpose: "Ecosystem-relevant topics or approaches that appear underrepresented and merit investigation, supported by topic evidence rather than missing data alone." },
  { key: "reference_inspiration", label: "Reference / inspiration", purpose: "Explicit human reference sources and qualified sources with useful ecosystem knowledge, topics or creative evidence." }
];

const clamp = (value, min = 0, max = 100) => Math.max(min, Math.min(max, value));
const round = (value, digits = 2) => Number.isFinite(value) ? Number(value.toFixed(digits)) : null;
const present = value => value !== null && value !== undefined && value !== "" && Number.isFinite(Number(value));
const numeric = value => present(value) ? Number(value) : null;
const logScore = (value, low, high) => {
  if (!present(value) || Number(value) < 0) return null;
  if (Number(value) <= low) return 0;
  if (Number(value) >= high) return 100;
  return clamp(100 * Math.log(Number(value) / low) / Math.log(high / low));
};
function mean(values) {
  const valid = values.filter(Number.isFinite);
  return valid.length ? valid.reduce((sum, value) => sum + value, 0) / valid.length : null;
}
function median(values) {
  const sorted = values.filter(Number.isFinite).sort((a, b) => a - b);
  if (!sorted.length) return null;
  const mid = Math.floor(sorted.length / 2);
  return sorted.length % 2 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
}
function percentile(values, p) {
  const sorted = values.filter(Number.isFinite).sort((a, b) => a - b);
  return sorted.length ? sorted[Math.min(sorted.length - 1, Math.ceil(sorted.length * p) - 1)] : null;
}
function weighted(parts) {
  const configured = parts.filter(part => Number.isFinite(part.weight) && part.weight > 0);
  const totalWeight = configured.reduce((sum, part) => sum + part.weight, 0);
  const available = configured.filter(part => Number.isFinite(part.value));
  const availableWeight = available.reduce((sum, part) => sum + part.weight, 0);
  if (!totalWeight || !availableWeight) {
    return { score: null, rawAvailableScore: null, coverage: 0, availableWeightPercent: 0, components: configured.map(part => ({
      name: part.name, score: null, weight: part.weight, coverage: 0, missing: true, evidence: part.evidence ?? null
    })) };
  }

  // Missing components must not silently disappear from the denominator. First
  // compute the mean of observed components, then shrink it toward a neutral 50
  // in proportion to how much of the configured component weight is actually
  // present. This is deliberately not a zero-fill: absent evidence is still null.
  const rawAvailableScore = available.reduce((sum, part) => sum + part.value * part.weight, 0) / availableWeight;
  const availableWeightPercent = availableWeight / totalWeight * 100;
  const score = 50 + (rawAvailableScore - 50) * (availableWeight / totalWeight);
  const coverage = configured.reduce((sum, part) => sum + (Number.isFinite(part.value) ? clamp(part.coverage ?? 100) : 0) * part.weight, 0) / totalWeight;
  return {
    score: round(clamp(score)),
    rawAvailableScore: round(rawAvailableScore),
    coverage: round(coverage),
    availableWeightPercent: round(availableWeightPercent),
    components: configured.map(part => ({
      name: part.name, score: Number.isFinite(part.value) ? round(part.value) : null,
      weight: part.weight, coverage: Number.isFinite(part.value) ? round(clamp(part.coverage ?? 100)) : 0,
      missing: !Number.isFinite(part.value), evidence: part.evidence ?? null
    }))
  };
}
function makeRating(queueKey, data = {}) {
  const score = Number.isFinite(data.score) ? round(clamp(data.score)) : null;
  const components = data.components ?? [];
  const missingComponents = components.filter(component => component.missing).map(component => String(component.name ?? "component").toLowerCase().replace(/[^a-z0-9]+/g, "_"));
  const uncertainty = [...(data.uncertainty ?? [])];
  const reasonCodes = [...(data.reasonCodes ?? [])];
  if (missingComponents.length) {
    uncertainty.push("one_or_more_scoring_components_missing");
    reasonCodes.push("score_shrunk_for_missing_components");
    for (const component of missingComponents) reasonCodes.push(`missing_component_${component}`);
  }
  if (Number.isFinite(data.coverage) && data.coverage < config.queueScoring.minimumCoverageForSupported) {
    uncertainty.push("scoring_evidence_coverage_below_supported_threshold");
  }
  return {
    queue_key: queueKey, score,
    confidence: round(clamp(data.confidence ?? 0)), coverage: round(clamp(data.coverage ?? 0)),
    sample_size: Math.max(0, Math.round(data.sampleSize ?? 0)),
    status: data.status ?? (score == null ? "insufficient_evidence" : "provisional"),
    rank: null, eligibility: data.eligibility ?? "qualification_pending",
    qualification_classification: data.qualification?.classification ?? "unknown",
    qualification_confidence: round((data.qualification?.confidence ?? 0) * 100),
    uncertainty: [...new Set(uncertainty)],
    reason_codes: [...new Set(reasonCodes)],
    evidence_refs: [...new Set(data.evidenceRefs ?? [])].slice(0, 20),
    rationale: data.rationale ?? "", components, evidence: data.evidence ?? {}
  };
}
function normalizeSeedKey(value) {
  return String(value ?? "").trim().replace(/^@/, "").toLowerCase().replace(/[^a-z0-9]/g, "");
}
function findSeed(channel, seeds) {
  const candidates = [channel.handle, channel.name, channel.channel_url?.split("/").filter(Boolean).at(-1)].filter(Boolean).map(normalizeSeedKey);
  return seeds.find(seed => [seed.handle, seed.channel_handle, seed.name, seed.channel_url].filter(Boolean)
    .some(value => candidates.includes(normalizeSeedKey(String(value).split("/").filter(Boolean).at(-1) ?? value)))) ?? null;
}
function asTag(value) {
  return String(typeof value === "string" ? value : value?.name ?? value?.tag ?? "").trim().toLowerCase().replace(/\s+/g, " ");
}
function topicRarity(features, qualifiedUrls) {
  const frequency = new Map();
  for (const [url, feature] of features) {
    if (!qualifiedUrls.has(url)) continue;
    for (const tag of new Set(feature.topic_tags.map(asTag).filter(Boolean))) frequency.set(tag, (frequency.get(tag) ?? 0) + 1);
  }
  const rarity = new Map();
  for (const [url, feature] of features) {
    const tags = [...new Set(feature.topic_tags.map(asTag).filter(Boolean))];
    const values = tags.map(tag => 100 / Math.sqrt(frequency.get(tag) ?? 1));
    rarity.set(url, values.length ? mean(values.map(v => clamp(v))) : null);
  }
  return { frequency, rarity };
}
function qualificationFor(channel) {
  if (channel.qualification_assessment) {
    return normalizeQualification(channel.qualification_assessment, { source: "llm" });
  }
  return normalizeQualification({
    classification: channel.ecosystem_classification,
    confidence: channel.ecosystem_classification_confidence,
    rationale: channel.ecosystem_reason,
    source: channel.ecosystem_classification_source ?? "rule_based"
  }, { source: channel.ecosystem_classification_source ?? "rule_based" });
}
function makeEligibility(queueKey, qualification, seed) {
  if (queueKey === "reference_inspiration" && seed) {
    if (qualification.classification === "irrelevant") return "explicit_reference_conflict";
    if (qualification.eligibility === "qualification_pending") return "explicit_reference_needs_qualification";
    return "explicit_reference";
  }
  if (qualification.classification === "irrelevant") return "ineligible_irrelevant";
  if (qualification.eligibility === "eligible_core") return "eligible_core";
  if (qualification.eligibility === "eligible_adjacent") return "eligible_adjacent";
  return "qualification_pending";
}
function qualificationUncertainty(q) {
  const flags = [...q.uncertainty_flags];
  if (q.source !== "llm") flags.push("llm_qualification_not_available_for_current_input");
  if (q.confidence < config.qualification.minimumConfidenceToQualify) flags.push("qualification_confidence_below_threshold");
  if (q.classification === "unknown") flags.push("ecosystem_classification_unknown");
  return [...new Set(flags)];
}
function sampleReliability(count, full = 15) { return clamp(count / full, 0, 1); }
function qualificationBase(channel, feature) {
  return feature.qualification;
}

/**
 * Evidence-led, queue-specific rankings. Eligibility is evaluated before a score is allowed to rank.
 * Static growth uses captured video fields only and never reads metric snapshots.
 */
export function scoreChannelQueues({ channels, referenceSeeds = [], now = new Date() }) {
  const featureMap = new Map(channels.map(channel => [channel.channel_url, buildSharedChannelEvidence(channel, now)]));
  const qualifiedUrls = new Set([...featureMap].filter(([, feature]) => feature.qualification.eligible).map(([url]) => url));
  const topicStats = topicRarity(featureMap, qualifiedUrls);
  const output = [];

  for (const channel of channels) {
    const url = channel.channel_url;
    const feature = featureMap.get(url);
    const q = qualificationBase(channel, feature);
    const seed = findSeed({ ...channel, handle: channel.handle ?? channel.channel_id }, referenceSeeds);
    const eligibility = Object.fromEntries(QUEUES.map(queue => [queue.key, makeEligibility(queue.key, q, seed)]));
    const videos = feature.videos;
    const withViews = videos.filter(video => video.views != null);
    const n = withViews.length;
    const medianViews = feature.median_video_views;
    const p90Views = feature.p90_video_views;
    const dated = withViews.filter(video => video.age_days != null && video.age_days >= config.queueScoring.breakout.minimumAgeDaysForAgeAdjustedViews);
    const ageAdjustedScore = logScore(feature.median_views_per_day_proxy, 1, 10000);
    const absoluteReachScore = logScore(medianViews, 100, 1000000);
    const priorSubs = config.queueScoring.breakout.smallChannelSubscriberPrior;
    const relativeReachScore = logScore(feature.smoothed_views_per_subscriber, 0.005, 3);
    const repeatabilityScore = feature.repeatability_percent == null ? null : clamp(feature.repeatability_percent);
    const consistencyScore = feature.median_to_p90_percent == null ? null : clamp(feature.median_to_p90_percent);
    const sampleConfidence = sampleReliability(n, config.queueScoring.breakout.fullSampleConfidenceVideos);
    const viewCoverage = channel.videos?.length ? n / channel.videos.length * 100 : 0;
    const metadataCount = [channel.channel_id, channel.description, channel.subscriber_count, channel.video_count, channel.total_view_count, channel.joined_date, channel.handle, channel.metadata_source].filter(v => v !== null && v !== undefined && v !== "").length;
    const metadataCoverage = metadataCount / 8 * 100;
    const uncertaintyBase = qualificationUncertainty(q);
    if (n < 10) uncertaintyBase.push("thin_video_sample");
    if (dated.length < 5) uncertaintyBase.push("limited_age_adjusted_sample");
    if (String(channel.subscriber_count_precision ?? "").toLowerCase().includes("abbreviated")) uncertaintyBase.push("subscriber_count_abbreviated");
    if (feature.estimated_date_count > 0) uncertaintyBase.push("some_publication_dates_estimated");

    const allowed = queueKey => eligibility[queueKey] === "eligible_core" || eligibility[queueKey] === "eligible_adjacent"
      || (queueKey === "reference_inspiration" && eligibility[queueKey] === "explicit_reference");
    const blockedRating = (queueKey, why) => makeRating(queueKey, {
      score: null, confidence: q.confidence * 100, coverage: 0, sampleSize: n,
      status: eligibility[queueKey] === "ineligible_irrelevant" ? "ineligible" : "needs_qualification",
      eligibility: eligibility[queueKey], qualification: q, uncertainty: [...uncertaintyBase, why],
      reasonCodes: [q.classification === "irrelevant" ? "ecosystem_irrelevant" : q.classification === "core" ? "ecosystem_core_below_confidence_threshold" : q.classification === "adjacent" ? "ecosystem_adjacent_below_confidence_threshold" : "ecosystem_unknown", why],
      evidenceRefs: [url], rationale: q.classification === "irrelevant"
        ? "The qualification evidence indicates that this channel is outside the target ecosystem; it is not ranked for this queue."
        : "The channel needs a sufficiently confident ecosystem qualification before it can compete in this ecosystem-focused queue.",
      evidence: { qualification: q, eligibility: eligibility[queueKey], required_action: "run_or_review_channel_qualification" }
    });

    // Queue 1: teachability and inspectable editorial approach, not popularity alone.
    if (!allowed("learn_from")) output.push({ channel_url: url, queue: seed && eligibility.learn_from === "qualification_pending" ? blockedRating("learn_from", "qualification_required") : blockedRating("learn_from", "not_eligible_for_ecosystem_learning_queue") });
    else {
      const focusSpecificity = numeric(q.focus_specificity);
      const rawPerformance = absoluteReachScore == null || repeatabilityScore == null
        ? null : 0.55 * absoluteReachScore + 0.45 * repeatabilityScore;
      const learnParts = [
        { name: "editorial_specialization_from_raw_metadata", value: focusSpecificity, weight: 0.28, coverage: focusSpecificity != null ? 100 : 0, evidence: focusSpecificity != null ? `Qualification analysis of channel metadata and sampled titles: focus-specificity ${focusSpecificity}/100` : "Raw-metadata qualification did not provide focus-specificity" },
        { name: "repeatable_performance_from_captured_videos", value: rawPerformance, weight: 0.24, coverage: n ? Math.min(100, n / 10 * 100) : 0, evidence: `median views ${medianViews ?? "unknown"}; ${feature.repeatable_count}/${n} sampled videos above the repeatability floor` },
        { name: "absolute_audience_reach", value: absoluteReachScore, weight: 0.16, coverage: n ? viewCoverage : 0, evidence: `median video views ${medianViews ?? "unknown"}` },
        { name: "raw_evidence_coverage", value: clamp((viewCoverage * 0.55) + metadataCoverage * 0.45), weight: 0.16, coverage: metadataCoverage, evidence: `${n}/${channel.videos?.length ?? 0} linked videos have view counts; metadata ${round(metadataCoverage)}%` }
      ];
      const score = weighted(learnParts);
      const sampleShrink = 0.65 + 0.35 * sampleReliability(n, 15);
      const finalScore = score.score == null ? null : 50 + (score.score - 50) * sampleShrink;
      const confidence = clamp(q.confidence * 45 + Math.min(1, n / 20) * 30 + Math.min(10, metadataCoverage / 10));
      const evidenceEnough = (focusSpecificity != null || rawPerformance != null || absoluteReachScore != null) && n >= 3;
      output.push({ channel_url: url, queue: makeRating("learn_from", {
        score: evidenceEnough ? finalScore : null, confidence, coverage: score.coverage, sampleSize: n,
        status: !evidenceEnough ? "insufficient_evidence" : (confidence >= 70 && n >= 10 && score.coverage >= config.queueScoring.minimumCoverageForSupported && q.confidence >= config.queueScoring.ranking.minimumConfidenceForSupported ? "supported" : "provisional"),
        eligibility: eligibility.learn_from, qualification: q, uncertainty: [...uncertaintyBase, ...(n < 10 ? ["learning_sample_is_thin"] : [])],
        reasonCodes: [q.classification === "core" ? "ecosystem_core" : "ecosystem_adjacent", focusSpecificity != null ? "raw_metadata_focus_signal_available" : null, rawPerformance != null ? "captured_video_performance_signal_available" : null, n < 10 ? "thin_video_sample" : null].filter(Boolean),
        evidenceRefs: [url, ...(channel.top_video_ids ?? []).slice(0, 5)],
        rationale: evidenceEnough ? `Queue-specific learning score uses qualification derived from raw channel metadata and captured-video performance; channel-profile/vocabulary outputs are excluded. Eligibility: ${eligibility.learn_from}. This is a research priority, not a universal quality verdict.` : "Insufficient raw metadata or captured-video evidence to recommend this channel as a learning exemplar.",
        components: score.components, evidence: { method: "queue_learn_from_v5_raw_metadata_only", qualification: q, eligibility: eligibility.learn_from, median_video_views: medianViews, repeatable_video_count: feature.repeatable_count, video_sample_size: n, metadata_coverage_percent: round(metadataCoverage), unadjusted_available_component_score: score.rawAvailableScore, available_component_weight_percent: score.availableWeightPercent }
      }) });
    }

    // Queue 2: robust static growth potential; subscriber ratios are smoothed and absolute reach matters.
    if (!allowed("breaking_out")) output.push({ channel_url: url, queue: blockedRating("breaking_out", "qualification_required_for_growth_ranking") });
    else {
      const growthParts = [
        { name: "absolute_median_video_reach", value: absoluteReachScore, weight: 0.25, coverage: viewCoverage, evidence: `median=${round(medianViews, 0)} views across ${n} videos` },
        { name: "smoothed_reach_relative_to_channel_size", value: relativeReachScore, weight: 0.20, coverage: present(channel.subscriber_count) ? 100 : 0, evidence: `median views / (subscribers + ${priorSubs}) = ${round(feature.smoothed_views_per_subscriber, 5)}` },
        { name: "lifetime_views_per_day_proxy", value: ageAdjustedScore, weight: 0.20, coverage: Math.min(100, dated.length / 10 * 100), evidence: `median lifetime views/day across ${dated.length} videos aged at least ${config.queueScoring.breakout.minimumAgeDaysForAgeAdjustedViews} days` },
        { name: "repeatability_above_minimum_reach", value: repeatabilityScore, weight: 0.25, coverage: Math.min(100, n / 15 * 100), evidence: `${feature.repeatable_count}/${n} videos reached at least max(1,000, 25% of subscribers)` },
        { name: "median_to_p90_consistency", value: consistencyScore, weight: 0.10, coverage: n >= 3 ? 100 : 0, evidence: `median/p90 view count=${round(feature.median_to_p90_percent, 1)}%` }
      ];
      const growth = weighted(growthParts);
      const minVideos = config.queueScoring.breakout.minVideosForScore;
      const enough = n >= minVideos && growth.score != null && (absoluteReachScore != null || repeatabilityScore != null);
      const reliability = sampleReliability(n, config.queueScoring.breakout.fullSampleConfidenceVideos);
      const finalScore = enough ? clamp(50 + (growth.score - 50) * (0.35 + 0.65 * reliability)) : null;
      const confidence = enough ? clamp(q.confidence * 40 + reliability * 35 + Math.min(1, dated.length / 10) * 15 + (metadataCoverage / 100) * 10 - (feature.estimated_date_count > 0 ? 5 : 0)) : 0;
      const topVideos = [...withViews].sort((a, b) => (b.views_per_day ?? -1) - (a.views_per_day ?? -1) || b.views - a.views).slice(0, 8);
      output.push({ channel_url: url, queue: makeRating("breaking_out", {
        score: finalScore, confidence, coverage: growth.coverage, sampleSize: n,
        status: !enough ? "insufficient_evidence" : (confidence >= 70 && n >= 15 && q.confidence >= config.queueScoring.ranking.minimumConfidenceForSupported && growth.coverage >= config.queueScoring.minimumCoverageForSupported && relativeReachScore != null && ageAdjustedScore != null && dated.length >= 5 ? "supported" : "provisional"),
        eligibility: eligibility.breaking_out, qualification: q,
        uncertainty: [...uncertaintyBase, ...(n < 10 ? ["small_sample_shrunk_toward_neutral"] : []), ...(String(channel.subscriber_count_precision ?? "").toLowerCase().includes("abbreviated") ? ["subscriber_count_precision_is_abbreviated"] : [])],
        reasonCodes: ["static_growth_potential_proxy", "no_snapshot_dependency", "smoothed_small_channel_denominator", "repeatability_and_absolute_reach_required", q.classification === "core" ? "ecosystem_core" : "ecosystem_adjacent", n < 10 ? "thin_video_sample" : null, dated.length < 5 ? "limited_age_adjusted_sample" : null].filter(Boolean),
        evidenceRefs: [url, ...topVideos.slice(0, 5).map(v => v.video_id ? `https://www.youtube.com/watch?v=${v.video_id}` : null).filter(Boolean)],
        rationale: enough ? `Static growth-potential score from smoothed channel-relative reach, absolute median views, repeatability above a 1,000-view floor, age-adjusted lifetime views/day and consistency. Sample size ${n}; ${dated.length} videos support the age-adjusted proxy. No snapshots are read; this does not prove current acceleration.` : `At least ${minVideos} videos with captured view counts and usable performance evidence are required; ${n} are available.`,
        components: growth.components,
        evidence: { method: "static_growth_potential_v2_evidence_led", snapshot_dependent: false, qualification: q, eligibility: eligibility.breaking_out,
          input_video_count: (channel.videos ?? []).length, video_count_with_views: n, dated_video_count_with_views: dated.length,
          median_video_views: round(medianViews, 0), p90_video_views: round(p90Views, 0), subscriber_count: numeric(channel.subscriber_count),
          subscriber_count_precision: channel.subscriber_count_precision ?? "unknown", smoothed_views_per_subscriber: round(feature.smoothed_views_per_subscriber, 6),
          median_lifetime_views_per_day_proxy: round(feature.median_views_per_day_proxy, 2), repeatable_video_count: feature.repeatable_count,
          repeatability_threshold_views: Math.max(1000, numeric(channel.subscriber_count) == null ? 0 : numeric(channel.subscriber_count) * 0.25),
          repeatability_percent: round(feature.repeatability_percent, 2), median_to_p90_percent: round(feature.median_to_p90_percent, 2),
          channel_age_years: round(feature.channel_age_years, 2), unadjusted_available_component_score: growth.rawAvailableScore,
          available_component_weight_percent: growth.availableWeightPercent, videos_used: topVideos.map(v => ({ video_id: v.video_id, title: v.title, views: v.views, published_at: v.date?.toISOString().slice(0, 10) ?? null, age_days: round(v.age_days, 1), lifetime_views_per_day_proxy: round(v.views_per_day, 2), date_precision: v.published_at_precision })) }
      }) });
    }

    // Queue 3: durable body of work, not age/scale alone.
    if (!allowed("durable_exemplars")) output.push({ channel_url: url, queue: blockedRating("durable_exemplars", "qualification_required_for_durable_ranking") });
    else {
      const age = feature.channel_age_years;
      const longevityScore = age == null ? null : clamp(age / 15 * 100);
      const catalogueScore = logScore(channel.video_count, 10, 5000);
      const lifetimeScale = logScore(channel.total_view_count, 10000, 1000000000);
      const repeatability = feature.repeatability_percent;
      const datedYears = withViews.map(v => v.date?.getUTCFullYear()).filter(Number.isFinite);
      const yearSpan = datedYears.length >= 2 ? Math.max(...datedYears) - Math.min(...datedYears) : null;
      const spanScore = yearSpan == null ? null : clamp(yearSpan / 10 * 100);
      const durableParts = [
        { name: "longevity", value: longevityScore, weight: 0.25, coverage: age == null ? 0 : 100, evidence: `channel age ${round(age, 2) ?? "unknown"} years` },
        { name: "declared_catalogue_depth", value: catalogueScore, weight: 0.20, coverage: present(channel.video_count) ? 100 : 0, evidence: `declared uploads ${channel.video_count ?? "unknown"}` },
        { name: "repeatable_video_performance", value: repeatability, weight: 0.25, coverage: Math.min(100, n / 15 * 100), evidence: `${feature.repeatable_count}/${n} sampled videos above the minimum reach floor` },
        { name: "median_video_reach", value: absoluteReachScore, weight: 0.15, coverage: viewCoverage, evidence: `median views ${medianViews ?? "unknown"}` },
        { name: "observed_time_span", value: spanScore, weight: 0.10, coverage: datedYears.length ? 100 : 0, evidence: yearSpan == null ? "publication-date span unavailable" : `${yearSpan} years between sampled publication dates` },
        { name: "lifetime_scale_context", value: lifetimeScale, weight: 0.05, coverage: present(channel.total_view_count) ? 100 : 0, evidence: `total views ${channel.total_view_count ?? "unknown"}; low weight so scale cannot dominate` }
      ];
      const durable = weighted(durableParts);
      const enough = n >= 3 && (age != null || catalogueScore != null) && durable.score != null;
      const reliability = sampleReliability(n, 20);
      const score = enough ? clamp(50 + (durable.score - 50) * (0.45 + 0.55 * reliability)) : null;
      const confidence = enough ? clamp(q.confidence * 45 + reliability * 30 + (age != null ? 10 : 0) + (catalogueScore != null ? 10 : 0) + (spanScore != null ? 5 : 0)) : 0;
      output.push({ channel_url: url, queue: makeRating("durable_exemplars", {
        score, confidence, coverage: durable.coverage, sampleSize: n,
        status: !enough ? "insufficient_evidence" : (confidence >= 70 && n >= 10 && yearSpan != null && durable.coverage >= config.queueScoring.minimumCoverageForSupported && q.confidence >= config.queueScoring.ranking.minimumConfidenceForSupported ? "supported" : "provisional"),
        eligibility: eligibility.durable_exemplars, qualification: q,
        uncertainty: [...uncertaintyBase, ...(n < 10 ? ["durability_sample_is_thin"] : []), ...(yearSpan == null ? ["temporal_span_not_established"] : [])],
        reasonCodes: ["durability_requires_repeatability", age != null ? "channel_age_known" : null, catalogueScore != null ? "catalogue_size_known" : null, n < 10 ? "thin_video_sample" : null].filter(Boolean),
        evidenceRefs: [url],
        rationale: enough ? "Durability combines longevity and catalogue depth with repeated performance and sampled temporal spread. Lifetime views have deliberately low weight; a large or old channel is not automatically an exemplar." : "A durability score needs qualification, at least three view-bearing videos, and at least one reliable longevity/catalogue signal.",
        components: durable.components, evidence: { method: "durable_exemplar_v5_raw_metadata_only", qualification: q, eligibility: eligibility.durable_exemplars, channel_age_years: round(age, 2), declared_video_count: channel.video_count ?? null, total_view_count: channel.total_view_count ?? null, video_sample_size: n, observed_publication_year_span: yearSpan, unadjusted_available_component_score: durable.rawAvailableScore, available_component_weight_percent: durable.availableWeightPercent }
      }) });
    }

    // Queue 4: niche opportunity needs topic evidence; data gaps are actions, not novelty.
    if (!allowed("unexplored_niches")) output.push({ channel_url: url, queue: blockedRating("unexplored_niches", "qualification_required_for_niche_opportunity") });
    else {
      const rarity = topicStats.rarity.get(url);
      const focusSpecificity = numeric(q.focus_specificity);
      const tags = [...new Set(q.topic_tags.map(asTag).filter(Boolean))];
      const nicheEvidence = tags.length > 0 || focusSpecificity != null;
      const topicRarityScore = tags.length ? rarity : null;
      const audienceSignal = absoluteReachScore;
      const nicheParts = [
        { name: "raw_metadata_topic_rarity", value: topicRarityScore, weight: 0.45, coverage: topicRarityScore == null ? 0 : 100, evidence: `${tags.length} qualification topic tags; corpus tag rarity ${round(rarity) ?? "unavailable"}` },
        { name: "raw_metadata_focus_specificity", value: focusSpecificity, weight: 0.30, coverage: focusSpecificity == null ? 0 : 100, evidence: q.focus_summary ?? "Qualification focus-specificity unavailable" },
        { name: "captured_audience_interest_context", value: audienceSignal, weight: 0.25, coverage: audienceSignal == null ? 0 : viewCoverage, evidence: `median views ${medianViews ?? "unknown"}; audience signal is context, not proof of demand` }
      ];
      const niche = weighted(nicheParts);
      const enough = nicheEvidence && n >= 3 && niche.score != null;
      const confidence = enough ? clamp(q.confidence * 50 + Math.min(1, n / 12) * 25 + (tags.length ? 15 : 0)) : 0;
      output.push({ channel_url: url, queue: makeRating("unexplored_niches", {
        score: enough ? niche.score : null, confidence, coverage: niche.coverage, sampleSize: n,
        status: !enough ? "insufficient_evidence" : (confidence >= 70 && n >= 8 && niche.coverage >= config.queueScoring.minimumCoverageForSupported && q.confidence >= config.queueScoring.ranking.minimumConfidenceForSupported && tags.length >= 2 && audienceSignal != null ? "supported" : "provisional"),
        eligibility: eligibility.unexplored_niches, qualification: q,
        uncertainty: [...uncertaintyBase, ...(tags.length < 2 ? ["niche_novelty_not_independently_supported"] : []), ...(n < 8 ? ["niche_evidence_sample_is_thin"] : [])],
        reasonCodes: ["niche_rarity_is_not_demand", tags.length ? "qualification_topic_tags_available" : null, !enough ? "more_topic_evidence_required" : null].filter(Boolean),
        evidenceRefs: [url, ...(channel.top_video_ids ?? []).slice(0, 5)],
        rationale: enough ? "Niche opportunity combines corpus-relative topic rarity, qualification focus-specificity from raw channel/video metadata, and captured audience-interest context. Channel profiles, vocabulary, embeddings and prior priority scores are excluded." : "The channel is qualified, but current raw metadata/topic evidence is too thin to assert a niche opportunity. Collect representative titles or refresh qualification evidence.",
        components: niche.components, evidence: { method: "unexplored_niche_v5_raw_metadata_only", qualification: q, eligibility: eligibility.unexplored_niches, topic_tags: tags, topic_tag_frequency: Object.fromEntries(tags.map(tag => [tag, topicStats.frequency.get(tag) ?? 0])), corpus_topic_rarity: round(rarity), topic_evidence_count: tags.length, video_sample_size: n, unadjusted_available_component_score: niche.rawAvailableScore, available_component_weight_percent: niche.availableWeightPercent, follow_up_action: enough ? "inspect niche and validate audience demand" : "collect evidence / qualify channel" }
      }) });
    }

    // Queue 5: qualification gates inferred candidates. Explicit seeds remain visible,
    // but an irrelevant or unqualified seed is flagged and cannot masquerade as a ranked exemplar.
    const refEligibility = eligibility.reference_inspiration;
    if (seed && refEligibility !== "explicit_reference") {
      const conflict = refEligibility === "explicit_reference_conflict";
      output.push({ channel_url: url, queue: makeRating("reference_inspiration", {
        score: null, confidence: q.confidence * 100, coverage: 0, sampleSize: n,
        status: conflict ? "explicit_reference_conflict" : "explicit_reference_needs_qualification",
        eligibility: refEligibility, qualification: q,
        uncertainty: [...uncertaintyBase, conflict ? "human_seed_conflicts_with_ecosystem_qualification" : "human_seed_requires_fresh_qualification"],
        reasonCodes: ["explicit_reference_seed", "seed_membership_separate_from_score", conflict ? "seed_ecosystem_conflict" : "seed_needs_qualification"],
        evidenceRefs: [url],
        rationale: conflict
          ? `This channel is an explicit human reference seed, but current qualification marks it irrelevant to the configured ecosystem (${q.rationale ?? "no rationale recorded"}). It is preserved for review but is not given an inferred inspiration rank.`
          : "This explicit human reference seed is preserved, but its current ecosystem qualification is missing, stale, or below the confidence threshold. Re-qualify or review it before ranking.",
        components: [], evidence: { method: "reference_inspiration_v3", explicit_reference_seed: true, seed_name: seed.name ?? seed.handle ?? null, qualification: q, eligibility: refEligibility, required_action: conflict ? "review_seed_or_ecosystem_boundary" : "refresh_qualification" }
      }) });
      continue;
    }
    if (!allowed("reference_inspiration")) {
      output.push({ channel_url: url, queue: blockedRating("reference_inspiration", "qualified_ecosystem_membership_required_for_inferred_reference") });
      continue;
    }
    const titleEvidenceScore = n ? clamp(100 * (1 - Math.exp(-n / 12))) : null;
    const metadataEvidenceScore = metadataCoverage > 0 ? metadataCoverage : null;
    // Topic evidence comes only from qualification analysis of raw metadata and
    // captured titles. Stage 03 profiles, vocabulary, concepts and patterns are excluded.
    const topicEvidenceCount = q.topic_tags.length;
    const topicEvidenceScore = topicEvidenceCount > 0
      ? clamp(8 * Math.log2(1 + topicEvidenceCount) + (q.focus_specificity ?? 0) * 0.15)
      : null;
    const relevanceBase = q.relevance_score ?? (q.classification === "core" ? 85 : q.classification === "adjacent" ? 65 : null);
    const relevanceEvidenceScore = relevanceBase == null ? null : clamp(relevanceBase * q.confidence);
    const refParts = [
      { name: "ecosystem_relevance_confidence", value: relevanceEvidenceScore, weight: 0.35, coverage: relevanceEvidenceScore == null ? 0 : q.confidence * 100, evidence: `${q.classification}; reported qualification confidence ${round(q.confidence * 100)}%; relevance score ${q.relevance_score ?? "fallback class prior"}` },
      { name: "raw_metadata_topic_evidence", value: topicEvidenceScore, weight: 0.30, coverage: topicEvidenceScore == null ? 0 : 100, evidence: `${q.topic_tags.length} qualification topic tags; logarithmic saturation` },
      { name: "representative_catalogue_evidence", value: titleEvidenceScore, weight: 0.20, coverage: n ? viewCoverage : 0, evidence: `${n} videos with views in current sample` },
      { name: "metadata_completeness", value: metadataEvidenceScore, weight: 0.15, coverage: metadataCoverage, evidence: `${round(metadataCoverage)}% of core channel metadata fields present` }
    ];
    const reference = weighted(refParts);
    const hasReferenceEvidence = reference.score != null && (n > 0 || q.topic_tags.length > 0 || seed);
    const refScore = hasReferenceEvidence ? reference.score : null;
    const refConfidence = clamp(q.confidence * 45 + Math.min(1, n / 15) * 25 + (topicEvidenceScore != null ? 20 : 0) + metadataCoverage / 10);
    const referenceSupported = refConfidence >= 70 && reference.coverage >= config.queueScoring.minimumCoverageForSupported
      && q.confidence >= config.queueScoring.ranking.minimumConfidenceForSupported;
    const referenceStatus = seed
      ? (refScore == null ? "explicit_reference_needs_evidence" : (referenceSupported ? "explicit_reference" : "explicit_reference_provisional"))
      : (refScore == null ? "insufficient_evidence" : (referenceSupported ? "supported" : "provisional"));
    output.push({ channel_url: url, queue: makeRating("reference_inspiration", {
      score: refScore, confidence: refScore == null ? 0 : refConfidence, coverage: reference.coverage, sampleSize: n + topicEvidenceCount,
      status: referenceStatus,
      eligibility: refEligibility, qualification: q,
      uncertainty: [...uncertaintyBase, ...(seed ? [] : ["inferred_reference_candidate_not_human_seed"]), ...(refScore == null ? ["reference_usefulness_evidence_missing"] : []), ...(reference.coverage < config.queueScoring.minimumCoverageForSupported ? ["reference_evidence_coverage_low"] : [])],
      reasonCodes: [seed ? "explicit_reference_seed" : "inferred_reference_candidate", seed ? "seed_membership_separate_from_score" : null, topicEvidenceScore != null ? "topic_evidence_available" : null, reference.coverage < config.queueScoring.minimumCoverageForSupported ? "low_reference_evidence_coverage" : null].filter(Boolean),
      evidenceRefs: [url, ...(channel.top_video_ids ?? []).slice(0, 5)],
      rationale: seed ? `Explicit human reference seed (${seed.name ?? seed.handle ?? "named seed"}). Seed membership is preserved separately from usefulness score; this score reflects qualification from raw metadata, captured-video catalogue evidence and metadata completeness.` : "Qualified inferred inspiration candidate scored on raw-metadata qualification, captured catalogue evidence and metadata completeness. Channel-profile/vocabulary outputs are excluded; human review is still required.",
      components: reference.components, evidence: { method: "reference_inspiration_v5_raw_metadata_only", qualification: q, eligibility: refEligibility, explicit_reference_seed: Boolean(seed), seed_name: seed?.name ?? null, topic_tags: q.topic_tags, video_sample_size: n, raw_available_component_score: reference.rawAvailableScore, available_component_weight_percent: reference.availableWeightPercent }
    }) });
  }

  // Only qualified rows with an actual score and a rankable status receive ranks.
  // Seed membership never bypasses qualification or improves a score by itself.
  const blockedStatuses = new Set(["ineligible", "needs_qualification", "insufficient_evidence", "explicit_reference_conflict", "explicit_reference_needs_qualification", "explicit_reference_needs_evidence"]);
  const tier = rating => rating.qualification_classification === "core" ? 0 : rating.qualification_classification === "adjacent" ? 1 : 9;
  for (const queue of QUEUES) {
    const ranked = output.filter(row => {
      if (row.queue.queue_key !== queue.key || row.queue.score == null || blockedStatuses.has(row.queue.status)) return false;
      if (queue.key === "reference_inspiration") return ["eligible_core", "eligible_adjacent", "explicit_reference"].includes(row.queue.eligibility);
      return ["eligible_core", "eligible_adjacent"].includes(row.queue.eligibility);
    }).sort((a, b) => tier(a.queue) - tier(b.queue) || b.queue.score - a.queue.score || b.queue.confidence - a.queue.confidence || a.channel_url.localeCompare(b.channel_url));
    ranked.forEach((row, index) => { row.queue.rank = index + 1; });
  }
  return { queues: QUEUES, ratings: output, scoring_version: config.queueScoring.version, diagnostics: {
    qualificationSources: Object.fromEntries([...new Set(channels.map(c => c.qualification_assessment ? "llm" : (c.ecosystem_classification_source ?? "rule_based")))].map(source => [source, channels.filter(c => (c.qualification_assessment ? "llm" : (c.ecosystem_classification_source ?? "rule_based")) === source).length])),
    eligibleCore: [...featureMap.values()].filter(f => f.qualification.eligibility === "eligible_core").length,
    eligibleAdjacent: [...featureMap.values()].filter(f => f.qualification.eligibility === "eligible_adjacent").length,
    qualificationPending: [...featureMap.values()].filter(f => f.qualification.eligibility === "qualification_pending").length,
    irrelevant: [...featureMap.values()].filter(f => f.qualification.classification === "irrelevant").length
  } };
}

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.