Docs/Skills and code/src/
src/topic-research/report.js
import { stamp } from "./util.js";
import { sourceUrl } from "./sources/youtube.js";
const dedupe = s => String(s ?? "").replace(/\b(\S+)\s+\1\b/gi, "$1");
const esc = s => String(s ?? "").replace(/\|/g, "\\|").replace(/\s*\n\s*/g, " ");
/** Source links for an item, one per distinct doc, pinned to the first verified timestamp. */
function cites(item, docByKey) {
const byDoc = new Map();
for (const ev of item.evidence) {
const cur = byDoc.get(ev.doc);
if (!cur || (ev.verified && !cur.verified)) byDoc.set(ev.doc, ev);
}
return [...byDoc.values()].map(ev => {
const doc = docByKey.get(ev.doc);
return `[${ev.doc} ${stamp(ev.t)}${ev.verified ? "" : "?"}](${sourceUrl(doc, ev.t)})`;
}).join(" ");
}
const strength = i => (i.source_count > 1 ? `${i.source_count} sources` : "1 source") + (i.verified_quotes ? "" : ", quote unverified");
const flags = i => [i.conflict && `⚠ ${i.conflict}`, i.note].filter(Boolean).join(" ");
export function renderReport({ topic, search, docs, extractions, synthesis: s }) {
const docByKey = new Map(docs.map(d => [d.key, d]));
const L = [];
L.push(`# Research brief: ${topic}`, "");
L.push(`_Built from ${s.sourcesUsed.length} YouTube transcripts. Every item links to the video at the timestamp it was said; \`?\` means the quote could not be matched verbatim to the transcript. Items backed by one source only are marked._`, "");
L.push("## The story in brief", "", `**${s.one_line}**`, "", s.overview, "");
L.push("## Timeline", "", "| When | What happened | Support | Sources |", "|---|---|---|---|");
for (const e of s.timeline) L.push(`| ${esc(e.date)} | ${esc(e.event)}${e.significance ? ` _${esc(e.significance)}_` : ""} ${esc(flags(e))} | ${strength(e)} | ${cites(e, docByKey)} |`);
L.push("");
L.push("## Hard numbers", "", "| Metric | Value | As of | Support | Sources |", "|---|---|---|---|---|");
for (const f of s.figures) L.push(`| ${esc(f.metric)}${f.context ? ` _(${esc(f.context)})_` : ""} | **${esc(dedupe(f.value))}** ${esc(flags(f))} | ${esc(f.as_of)} | ${strength(f)} | ${cites(f, docByKey)} |`);
L.push("");
L.push("## Shocking / surprising points", "");
s.surprises.forEach((p, i) => L.push(`${i + 1}. **${p.point}** (${p.strength ?? "?"}; ${strength(p)}) ${p.why_surprising ? `— ${p.why_surprising}` : ""} ${flags(p)} ${cites(p, docByKey)}`));
L.push("");
L.push("## Why it happened", "");
for (const c of s.causes) L.push(`- **${c.factor}** _(${c.kind}, ${strength(c)})_ — ${c.explanation} ${flags(c)} ${cites(c, docByKey)}`);
L.push("");
L.push("## Key people and entities", "");
for (const e of s.entities ?? []) L.push(`- **${e.name}** (${e.type}) — ${e.role}`);
L.push("");
if (s.contested?.length) {
L.push("## Contested or shaky claims", "");
for (const c of s.contested) L.push(`- ${c.claim} — _${c.why_contested}_`);
L.push("");
}
L.push("## Still open (what the sources do not settle)", "");
for (const q of s.open_questions ?? []) L.push(`- **${q.question}** ${q.why ? `— ${q.why}` : ""}`);
L.push("");
L.push("## Next: verify with Google AI Mode", "", "_Queued queries (AI Mode source not wired in yet):_", "");
for (const q of s.verification_queries ?? []) L.push(`- ${q}`);
L.push("");
L.push("## Sources", "", "| Key | Video | Channel | Views | Length | Lang | Facts (verified/total) |", "|---|---|---|---|---|---|---|");
for (const d of docs) {
const e = extractions.find(x => x.key === d.key);
const total = e ? Object.values(e.stats).reduce((a, x) => a + x.total, 0) : 0;
const ok = e ? Object.values(e.stats).reduce((a, x) => a + x.verified, 0) : 0;
const used = s.sourcesUsed.includes(d.key) ? "" : d.error ? " _(no captions available)_" : " _(excluded: no usable speech or off-topic)_";
L.push(`| ${d.key} | [${esc(d.meta.title)}](${sourceUrl(d)})${used} | ${esc(d.meta.channel)} | ${d.meta.views?.toLocaleString("en-IN") ?? "?"} | ${stamp(d.meta.duration_seconds)} | ${d.lang ?? (d.error ? "no transcript" : "?")} | ${e ? `${ok}/${total}` : "-"} |`);
}
L.push("", "## Method and caveats", "",
`- Search: ${search.queries.length} fixed query templates, ${search.candidatesSeen} videos seen, ${search.candidatesKept} passed the topic/noise filter, top ${search.selected.length} by a fixed score (log views + query hits + length + framing words).`,
"- Extraction: one structured LLM pass per transcript (temperature 0.1, all answers cached by prompt hash). Quotes are verified in code against the transcript text.",
"- Synthesis merges facts across videos; items with no valid supporting fact id are dropped. Support counts are computed in code, not by the model.",
"- Limits: transcripts are auto-captions; YouTube explainers repeat each other, so \"several sources\" can still be one original claim. Treat all numbers as leads to confirm, not as facts, until checked against filings or news.");
return L.join("\n");
}
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.