Docs/Skills and code/src/
src/stages/31-within-channel-performance.js
import { filterQualifiedRows } from "../analysis/qualification-scope.js";
import crypto from "node:crypto";
import path from "node:path";
import Database from "better-sqlite3";
import { config as projectConfig } from "../../config.js";
import { analyzeWithinChannelCorpus } from "../analysis/within-channel-performance.js";
import { loadWithinChannelInput, persistWithinChannelAnalysis } from "../analysis/within-channel-performance-store.js";
import { writeWithinChannelPerformanceReports } from "../analysis/within-channel-performance-report.js";
const args = process.argv.slice(2);
const has = flag => args.includes(flag);
const argValue = name => args.find(value => value.startsWith(`${name}=`))?.slice(name.length + 1);
const dryRun = has("--dry-run");
const generatedAt = new Date().toISOString();
const parsedNow = argValue("--as-of") ? Date.parse(argValue("--as-of")) : Date.parse(generatedAt);
if (!Number.isFinite(parsedNow)) throw new Error("--as-of must be a valid ISO date/time.");
const runId = `${generatedAt.replaceAll(":", "-").replaceAll(".", "-")}-${crypto.randomUUID().slice(0, 8)}`;
const root = process.cwd();
const databasePath = path.resolve(projectConfig.dbPath);
const db = new Database(databasePath, { fileMustExist: true });
db.pragma("foreign_keys = ON");
const analysisConfig = {
absoluteReachFloor: 1000,
subscriberReachFraction: 0.25,
minAgeCohortSize: 20,
sampleThresholds: { insufficientMax: 4, preliminaryMax: 9, initialOutlierMax: 19, distributionMax: 49, subgroupMin: 50 },
lifetimeOutlierMethod: "log1p_views_median_mad; robust_z>=2.5 potential, >=3.5 strong; ratio fallback only when MAD=0",
ageAdjustedMethod: "exact-calendar-publication-date views/day; channel-relative log1p median/MAD plus separate global age-cohort baseline",
viewSelection: "latest observation among current videos row and newest non-null video_metric_snapshots row; precision retained",
deduplication: "UNION DISTINCT (channel_url, video_id) from channel_videos and videos.channel_url",
scoringBoundary: "observational_only; existing queue score and rank tables are not read or modified"
};
try {
console.log("[within-channel:analyze] Starting", {
runId,
database: databasePath,
mode: dryRun ? "DRY RUN (no tables or reports written)" : "PERSIST NEW ANALYSIS TABLES",
asOf: new Date(parsedNow).toISOString(),
queueScoresWillChange: false
});
const input = loadWithinChannelInput(db);
input.channels = filterQualifiedRows(db, input.channels, "channel", { label: "31-within-channel-performance.js" });
const eligibleUrls = new Set(input.channels.map(channel => channel.channel_url));
input.videosByChannel = new Map([...input.videosByChannel.entries()].filter(([channelUrl]) => eligibleUrls.has(channelUrl)));
input.uniquePairCount = [...input.videosByChannel.values()].reduce((sum, videos) => sum + videos.length, 0);
const channelCounts = input.channels.length;
const linkedCount = input.uniquePairCount;
console.log("[within-channel:analyze] Source population", {
channels: channelCounts,
rawChannelVideoRelationshipRows: input.rawRelationCount,
deduplicatedChannelVideoPairs: input.rawUniquePairCount,
duplicateRelationshipRowsRemoved: input.rawRelationCount - input.rawUniquePairCount,
supplementalPairsFromVideosTable: input.supplementalVideoPairs,
finalUniqueChannelVideoPairs: linkedCount,
videosWithRelationships: [...input.videosByChannel.values()].reduce((sum, rows) => sum + rows.length, 0)
});
const result = analyzeWithinChannelCorpus({
channels: input.channels,
videosByChannel: input.videosByChannel,
nowMs: parsedNow,
config: analysisConfig
});
const summary = {
channels_analyzed: result.profiles.length,
channels_with_zero_eligible_views: result.profiles.filter(row => row.eligible_view_count === 0).length,
channels_with_under_5_eligible_views: result.profiles.filter(row => row.eligible_view_count < 5).length,
channels_with_5_to_9_eligible_views: result.profiles.filter(row => row.eligible_view_count >= 5 && row.eligible_view_count <= 9).length,
channels_with_10_to_19_eligible_views: result.profiles.filter(row => row.eligible_view_count >= 10 && row.eligible_view_count <= 19).length,
channels_with_20_to_49_eligible_views: result.profiles.filter(row => row.eligible_view_count >= 20 && row.eligible_view_count <= 49).length,
channels_with_50_plus_eligible_views: result.profiles.filter(row => row.eligible_view_count >= 50).length,
unique_channel_video_pairs: linkedCount,
video_outlier_rows: result.outliers.length,
eligible_video_records: result.profiles.reduce((sum, row) => sum + row.eligible_view_count, 0),
reliable_dated_video_records: result.profiles.reduce((sum, row) => sum + row.reliable_dated_view_count, 0),
age_cohort_count: result.cohortBenchmarks.length,
queue_evidence_rows: result.queueEvidence.length,
existing_queue_scores_modified: false
};
console.log("[within-channel:analyze] Computation complete", summary);
console.log("[within-channel:analyze] Sample profiles", result.profiles.slice(0, 5).map(row => ({
channel: row.channel_name,
sample: row.eligible_view_count,
medianViews: row.median_views,
p90Views: row.p90_views,
top5Share: row.top_5_view_share,
lifetimeCandidates: row.outlier_candidate_count,
datedSample: row.reliable_dated_view_count,
assessment: row.sample_assessment
})));
if (dryRun) {
console.log("[within-channel:analyze] Dry run complete; no database tables or report files were written.");
} else {
const persisted = persistWithinChannelAnalysis(db, { runId, generatedAt, input, result, config: analysisConfig, summary });
console.log("[within-channel:analyze] Persisted independent analytical layer", persisted);
writeWithinChannelPerformanceReports(db, root, runId);
console.log("[within-channel:analyze] Complete. Existing queue scores/ranks remain unchanged.");
}
} catch (error) {
console.error("[within-channel:analyze] Failed", { runId, database: databasePath, message: error.message, stack: error.stack });
process.exitCode = 1;
} finally {
db.close();
}
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.