asingh15's picture
Publish self-reflection-best feedback trajectories
7265291 verified
Raw
History Blame Contribute Delete
38 kB
"use strict";
const FALLBACK_FEEDBACK = "Revise the review to better match the rubric's content, tone, style, and length.";
const state = {
index: null,
trajectories: [],
visible: [],
checkpoints: [],
payload: null,
activeRound: 0,
view: "trajectory",
};
const byId = (id) => document.getElementById(id);
const finite = (value) => value !== null && value !== undefined && Number.isFinite(Number(value));
const number = (value) => (finite(value) ? Number(value) : null);
function formatScore(value, digits = 3) {
return finite(value) ? Number(value).toFixed(digits) : "N/A";
}
function formatSigned(value, digits = 3) {
if (!finite(value)) return "N/A";
const numeric = Number(value);
return `${numeric > 0 ? "+" : ""}${numeric.toFixed(digits)}`;
}
function formatPercent(value, digits = 1) {
if (!finite(value)) return "N/A";
return `${(Number(value) * 100).toFixed(digits)}%`;
}
function mean(values) {
const valid = values.filter(finite).map(Number);
return valid.length ? valid.reduce((total, value) => total + value, 0) / valid.length : null;
}
function words(value) {
return String(value || "").trim().split(/\s+/).filter(Boolean).length;
}
function cleanResearchText(value) {
return String(value || "")
.replace(/<br\s*\/?>/gi, "\n")
.replace(/<\/?(?:response|rubric)>/gi, "")
.replace(/&(#x[0-9a-f]+|#\d+|quot|amp|apos|lt|gt|nbsp);/gi, (match, entity) => {
const named = { quot: '"', amp: "&", apos: "'", lt: "<", gt: ">", nbsp: " " };
const lowered = entity.toLowerCase();
if (Object.prototype.hasOwnProperty.call(named, lowered)) return named[lowered];
const numeric = lowered.startsWith("#x")
? Number.parseInt(lowered.slice(2), 16)
: Number.parseInt(lowered.slice(1), 10);
if (!Number.isInteger(numeric) || numeric < 0 || numeric > 0x10ffff) return match;
try {
return String.fromCodePoint(numeric);
} catch (_error) {
return match;
}
})
.trim();
}
function appendInline(container, text) {
const chunks = String(text).split(/(\*\*[^*]+\*\*)/g);
chunks.forEach((chunk) => {
if (chunk.startsWith("**") && chunk.endsWith("**") && chunk.length > 4) {
const strong = document.createElement("strong");
strong.textContent = chunk.slice(2, -2);
container.appendChild(strong);
} else {
container.appendChild(document.createTextNode(chunk));
}
});
}
function renderStructured(container, value) {
container.replaceChildren();
const text = cleanResearchText(value);
if (!text) {
const empty = document.createElement("p");
empty.textContent = "No text was logged.";
container.appendChild(empty);
return;
}
const blocks = text.split(/\n\s*\n/).filter((block) => block.trim());
blocks.forEach((block) => {
const lines = block.split("\n").filter((line) => line.trim());
const numbered = lines.length > 1 && lines.every((line) => /^\s*\d+[.)]\s+/.test(line));
if (numbered) {
const list = document.createElement("ol");
lines.forEach((line) => {
const item = document.createElement("li");
appendInline(item, line.replace(/^\s*\d+[.)]\s+/, ""));
list.appendChild(item);
});
container.appendChild(list);
return;
}
const paragraph = document.createElement("p");
lines.forEach((line, index) => {
if (index) paragraph.appendChild(document.createElement("br"));
appendInline(paragraph, line);
});
container.appendChild(paragraph);
});
}
function addOption(select, value, label) {
const option = document.createElement("option");
option.value = String(value);
option.textContent = label;
select.appendChild(option);
}
function badge(label, className = "") {
const element = document.createElement("span");
element.className = `badge ${className}`.trim();
element.textContent = label;
return element;
}
function metricCell(label, value, detail, className = "") {
const cell = document.createElement("div");
cell.className = `metric-cell ${className}`.trim();
const name = document.createElement("span");
name.textContent = label;
const strong = document.createElement("strong");
strong.textContent = value;
cell.append(name, strong);
if (detail) {
const small = document.createElement("small");
small.textContent = detail;
cell.appendChild(small);
}
return cell;
}
function scorePill(label, value, className = "") {
const pill = document.createElement("div");
pill.className = `score-pill ${className}`.trim();
const name = document.createElement("span");
name.textContent = label;
const strong = document.createElement("strong");
strong.textContent = value;
pill.append(name, strong);
return pill;
}
function deltaClass(value) {
if (!finite(value) || Math.abs(Number(value)) < 1e-9) return "";
return Number(value) > 0 ? "positive" : "negative";
}
function outcomeLabel(value) {
const labels = { improved: "Gold improved", unchanged: "Gold unchanged", worsened: "Gold worsened" };
return labels[value] || String(value || "Outcome unavailable");
}
function trajectorySummary(record, payload = null) {
return (payload && (payload.trajectory || payload.summary)) || record || {};
}
function trajectoryId(record) {
return String(record.id || record.trajectory_id || record.path || "");
}
function trajectoryPath(record) {
return String(record.path || record.data_path || `data/trajectories/${trajectoryId(record)}.json`);
}
function checkpointId(record) {
return String(record.checkpoint_id || `${record.run_id || record.run_label || "run"}:${record.step}:${record.uid}`);
}
function checkpointLabel(checkpoint) {
const title = checkpoint.title || checkpoint.context_label || checkpoint.uid || "Source example";
const run = checkpoint.run_label || checkpoint.run_id || "run";
return `Step ${checkpoint.step} · ${title} · ${run}`;
}
function buildCheckpointIndex() {
const supplied = Array.isArray(state.index.checkpoints) ? state.index.checkpoints : [];
const byKey = new Map(supplied.map((item) => [String(item.id || checkpointId(item)), { ...item }]));
state.trajectories.forEach((record) => {
const id = checkpointId(record);
if (!byKey.has(id)) {
byKey.set(id, {
id,
run_id: record.run_id,
run_label: record.run_label,
step: record.step,
uid: record.uid,
title: record.title,
author: record.author,
category: record.category,
});
}
const checkpoint = byKey.get(id);
checkpoint.id = id;
});
state.checkpoints = [...byKey.values()].sort((a, b) => Number(a.step) - Number(b.step) || String(a.run_id).localeCompare(String(b.run_id)));
}
function populateCheckpointSelect(preferred = null) {
const select = byId("checkpoint-select");
const current = preferred || select.value;
select.replaceChildren();
state.checkpoints.forEach((checkpoint) => addOption(select, checkpoint.id, checkpointLabel(checkpoint)));
if (state.checkpoints.some((checkpoint) => checkpoint.id === current)) select.value = current;
if (!select.value && state.checkpoints.length) select.value = state.checkpoints[0].id;
}
function applyTrajectoryFilter(preferredId = null) {
const checkpoint = byId("checkpoint-select").value;
const outcome = byId("outcome-select").value;
let visible = state.trajectories.filter((record) => checkpointId(record) === checkpoint);
if (outcome !== "all") visible = visible.filter((record) => String(record.outcome) === outcome);
if (!visible.length && outcome !== "all") {
byId("outcome-select").value = "all";
visible = state.trajectories.filter((record) => checkpointId(record) === checkpoint);
}
state.visible = visible.sort((a, b) => Number(a.rubric_idx) - Number(b.rubric_idx) || Number(a.judge_idx) - Number(b.judge_idx));
const select = byId("trajectory-select");
const current = preferredId || select.value;
select.replaceChildren();
state.visible.forEach((record) => {
const tie = Number(record.tie_count || 1) > 1 ? ` · ${record.tie_count}-way tie` : "";
addOption(
select,
trajectoryId(record),
`Rubric ${record.rubric_idx} · path ${record.judge_idx} · selected r${record.selected_round}${tie} · ${outcomeLabel(record.outcome)}`,
);
});
if (state.visible.some((record) => trajectoryId(record) === current)) select.value = current;
if (!select.value && state.visible.length) select.value = trajectoryId(state.visible[0]);
updateTrajectoryPosition();
}
function selectedRecord() {
const id = byId("trajectory-select").value;
return state.visible.find((record) => trajectoryId(record) === id) || null;
}
function updateTrajectoryPosition() {
const id = byId("trajectory-select").value;
const index = state.visible.findIndex((record) => trajectoryId(record) === id);
byId("trajectory-position").textContent = index >= 0 ? `${index + 1} of ${state.visible.length}` : "No paths";
byId("previous-trajectory").disabled = index <= 0;
byId("next-trajectory").disabled = index < 0 || index >= state.visible.length - 1;
}
async function loadSelectedTrajectory() {
const record = selectedRecord();
updateTrajectoryPosition();
if (!record) {
showError("No trajectory matches these filters.");
return;
}
byId("loading").hidden = false;
byId("trajectory-content").hidden = true;
byId("error").hidden = true;
try {
const response = await fetch(trajectoryPath(record));
if (!response.ok) throw new Error(`HTTP ${response.status}`);
state.payload = await response.json();
state.activeRound = 0;
renderTrajectory(record, state.payload);
byId("loading").hidden = true;
byId("trajectory-content").hidden = false;
} catch (error) {
showError(`Could not load this trajectory (${error.message}).`);
}
}
function showError(message) {
byId("loading").hidden = true;
byId("trajectory-content").hidden = true;
byId("error").textContent = message;
byId("error").hidden = false;
}
function extractContext(payload) {
if (typeof payload.context === "string") return { text: payload.context };
return payload.context || payload.source_context || {};
}
function extractRubric(payload) {
if (typeof payload.rubric === "string") return { parsed: payload.rubric, generated: payload.rubric };
return payload.rubric || {};
}
function extractPrompts(payload) {
return payload.prompts || payload.prompt || {};
}
function renderTrajectory(record, payload) {
const summary = trajectorySummary(record, payload);
const checkpoint = payload.checkpoint || {};
const context = extractContext(payload);
const rubric = extractRubric(payload);
const rounds = payload.rounds || payload.turns || [];
payload.rounds = rounds;
const title = context.title || checkpoint.title || record.title || "Target book";
byId("record-eyebrow").textContent = `Step ${checkpoint.step ?? record.step} · ${checkpoint.run_label || record.run_label || checkpoint.run_id || record.run_id}`;
byId("record-title").textContent = title;
byId("record-subtitle").textContent = [context.author || record.author, context.category || record.category].filter(Boolean).join(" · ");
byId("record-id").textContent = `${checkpoint.uid || record.uid} · rubric ${summary.rubric_idx ?? record.rubric_idx} · path ${summary.judge_idx ?? record.judge_idx}`;
renderSummary(summary, rounds);
renderContext(context, payload.target_response || payload.target || payload.reference_response || "");
renderPrompts(extractPrompts(payload));
renderRubric(rubric, summary, record);
renderRoundTrack(rounds);
renderRoundDetail(rounds);
renderHistory(rounds);
refreshIcons();
}
function summaryValue(summary, ...keys) {
for (const key of keys) if (summary[key] !== undefined) return summary[key];
return null;
}
function renderSummary(summary, rounds) {
const initialGold = summaryValue(summary, "initial_gold") ?? rounds[0]?.gold_score;
const lastGold = summaryValue(summary, "last_gold") ?? rounds.at(-1)?.gold_score;
const selectedGold = summaryValue(summary, "selected_gold", "selected_gold_weighted");
const bestGold = summaryValue(summary, "best_gold", "oracle_best_gold") ?? Math.max(...rounds.map((row) => Number(row.gold_score)));
const selectedDelta = finite(selectedGold) && finite(initialGold) ? Number(selectedGold) - Number(initialGold) : null;
const spearman = summaryValue(summary, "proxy_gold_spearman", "spearman");
const tieCount = Number(summary.tie_count || summary.selected_tie_count || 1);
const selectedRound = summary.selected_round;
const container = byId("trajectory-summary");
container.replaceChildren(
metricCell("Initial gold", formatScore(initialGold), "round 0", "gold"),
metricCell("Selected gold", formatScore(selectedGold), tieCount > 1 ? `mean of ${tieCount} tied rounds` : `round ${selectedRound}`, "gold"),
metricCell("Selected change", formatSigned(selectedDelta), "selected minus initial", deltaClass(selectedDelta)),
metricCell("Last gold", formatScore(lastGold), `round ${rounds.length - 1}`, "gold"),
metricCell("Oracle best gold", formatScore(bestGold), "best logged state", "gold"),
metricCell("Proxy-gold rank", formatScore(spearman), "Spearman across valid rounds", "proxy"),
);
}
function renderContext(context, target) {
const metadata = [
["Title", context.title],
["Author", context.author],
["Category", context.category],
["Store", context.store_label || context.store],
["Subtitle", context.subtitle],
["Price", context.price],
].filter(([, value]) => value !== null && value !== undefined && String(value).trim());
const list = byId("context-meta");
list.replaceChildren();
metadata.forEach(([label, value]) => {
const wrapper = document.createElement("div");
const term = document.createElement("dt");
term.textContent = label;
const definition = document.createElement("dd");
definition.textContent = String(value);
wrapper.append(term, definition);
list.appendChild(wrapper);
});
renderStructured(byId("context-text"), context.text || context.context || "");
renderStructured(byId("target-response"), target);
resetClamp("context-text", "context-toggle", "Show full context", "Collapse context");
}
function renderMessages(container, messages) {
container.replaceChildren();
(messages || []).forEach((message) => {
const wrapper = document.createElement("article");
wrapper.className = "message";
const role = document.createElement("div");
role.className = "message-role";
role.textContent = message.role || "message";
const content = document.createElement("div");
content.className = "message-content";
content.textContent = cleanResearchText(message.content || "");
wrapper.append(role, content);
container.appendChild(wrapper);
});
if (!messages || !messages.length) {
const empty = document.createElement("p");
empty.textContent = "No prompt messages were exported.";
container.appendChild(empty);
}
}
function renderPrompts(prompts) {
const candidateMessages = prompts.candidate_messages || prompts.icl_messages || [];
const rubricMessages = prompts.rubric_messages || prompts.rubric_prompt || [];
renderMessages(byId("candidate-messages"), candidateMessages);
renderMessages(byId("rubric-messages"), rubricMessages);
byId("candidate-prompt-size").textContent = `${candidateMessages.length} messages · ${candidateMessages.reduce((total, item) => total + words(item.content), 0).toLocaleString()} words`;
byId("rubric-prompt-size").textContent = `${rubricMessages.length} messages · ${rubricMessages.reduce((total, item) => total + words(item.content), 0).toLocaleString()} words`;
}
function renderRubric(rubric, summary, record) {
const generated = rubric.generated || rubric.generated_rubric || rubric.parsed || rubric.parsed_rubric || "";
const parsed = rubric.parsed || rubric.parsed_rubric || generated;
renderStructured(byId("rubric-text"), generated);
renderStructured(byId("parsed-rubric"), parsed);
const exact = Boolean(parsed);
byId("rubric-status").textContent = exact ? "Exact logged rubric" : "Rubric unavailable";
byId("rubric-status").className = `status-badge ${exact ? "valid" : ""}`;
byId("rubric-eyebrow").textContent = `Rubric ${summary.rubric_idx ?? record.rubric_idx} · shared by this judge path`;
byId("parsed-rubric-size").textContent = `${words(parsed).toLocaleString()} words`;
byId("parsed-rubric-details").hidden = parsed === generated;
resetClamp("rubric-text", "rubric-toggle", "Show full rubric", "Collapse rubric");
}
function resetClamp(contentId, buttonId, collapsedLabel, expandedLabel) {
const content = byId(contentId);
const button = byId(buttonId);
content.classList.add("is-clamped");
button.setAttribute("aria-expanded", "false");
button.textContent = collapsedLabel;
button.dataset.collapsedLabel = collapsedLabel;
button.dataset.expandedLabel = expandedLabel;
}
function renderRoundTrack(rounds) {
const track = byId("round-track");
track.replaceChildren();
rounds.forEach((round, index) => {
const button = document.createElement("button");
const tie = Number(round.selection_weight || 0) > 0;
button.type = "button";
button.className = `round-button${index === state.activeRound ? " active" : ""}${tie ? " tie" : ""}`;
button.setAttribute("role", "option");
button.setAttribute("aria-selected", String(index === state.activeRound));
button.dataset.round = String(index);
const top = document.createElement("div");
top.className = "round-button-top";
const label = document.createElement("span");
label.textContent = `Round ${round.round ?? index}`;
const mark = document.createElement("span");
mark.className = "round-button-mark";
mark.textContent = round.selected_final ? "returned" : tie ? "top" : "";
top.append(label, mark);
const scores = document.createElement("div");
scores.className = "round-button-scores";
const proxy = document.createElement("span");
proxy.textContent = `P ${formatScore(round.proxy_score, 2)}`;
const gold = document.createElement("span");
gold.textContent = `G ${formatScore(round.gold_score, 2)}`;
scores.append(proxy, gold);
const delta = index ? Number(round.gold_score) - Number(rounds[index - 1].gold_score) : 0;
const change = document.createElement("div");
change.className = `round-button-delta ${deltaClass(delta)}`.trim();
change.textContent = index ? `${formatSigned(delta, 2)} gold` : "initial state";
button.append(top, scores, change);
button.addEventListener("click", () => setActiveRound(index));
track.appendChild(button);
});
updateRoundControls(rounds.length);
}
function updateRoundControls(length) {
byId("previous-round").disabled = state.activeRound <= 0;
byId("next-round").disabled = state.activeRound >= length - 1;
}
function setActiveRound(index) {
const rounds = state.payload?.rounds || [];
if (!rounds.length) return;
state.activeRound = Math.max(0, Math.min(index, rounds.length - 1));
renderRoundTrack(rounds);
renderRoundDetail(rounds);
renderHistory(rounds);
}
function roundBadges(round) {
const fragment = document.createDocumentFragment();
if (round.selected_final) fragment.appendChild(badge("Returned representative", "selected"));
if (Number(round.selection_weight || 0) > 0) {
const ties = (state.payload?.rounds || []).filter((item) => Number(item.selection_weight || 0) > 0).length;
fragment.appendChild(badge(ties > 1 ? `Reward weight ${formatScore(round.selection_weight, 3)}` : "Top proxy round", ties > 1 ? "tie" : "selected"));
}
if (!round.proxy_valid) fragment.appendChild(badge("Invalid proxy output", "invalid"));
return fragment;
}
function responseScores(round, previous = null) {
const container = document.createElement("div");
container.className = "response-scores";
const proxy = document.createElement("div");
proxy.className = "response-score proxy";
proxy.append(Object.assign(document.createElement("span"), { textContent: "Proxy" }), Object.assign(document.createElement("strong"), { textContent: formatScore(round.proxy_score) }));
const gold = document.createElement("div");
gold.className = "response-score gold";
gold.append(Object.assign(document.createElement("span"), { textContent: "Gold" }), Object.assign(document.createElement("strong"), { textContent: formatScore(round.gold_score) }));
const delta = previous && finite(round.gold_score) && finite(previous.gold_score) ? Number(round.gold_score) - Number(previous.gold_score) : 0;
const change = document.createElement("div");
change.className = `response-score ${previous ? deltaClass(delta) : ""}`.trim();
change.append(Object.assign(document.createElement("span"), { textContent: previous ? "Gold vs prior" : "Gold change" }), Object.assign(document.createElement("strong"), { textContent: previous ? formatSigned(delta) : "Initial" }));
container.append(proxy, gold, change);
return container;
}
function renderRoundDetail(rounds) {
const index = state.activeRound;
const current = rounds[index];
const next = rounds[index + 1] || null;
if (!current) return;
const feedback = current.feedback_used || current.feedback || FALLBACK_FEEDBACK;
const fallback = Boolean(current.feedback_fallback) || (!current.feedback && !current.proxy_valid);
byId("feedback-eyebrow").textContent = fallback ? "Fallback feedback after invalid judge output" : `Judge feedback for round ${current.round ?? index}`;
byId("feedback-title").textContent = next ? `Instruction used to generate round ${next.round ?? index + 1}` : "Terminal feedback (no later revision)";
byId("feedback-text").textContent = feedback;
byId("feedback-note").textContent = next
? "The candidate generator also received the full earlier candidate, feedback, and proxy-score history. Gold rewards were hidden from it."
: "This feedback was scored and logged, but the configured round limit ended before another candidate was generated.";
byId("feedback-note").className = `feedback-note${fallback ? " fallback" : ""}`;
const pills = byId("feedback-score-pills");
pills.replaceChildren(
scorePill("Current proxy", formatScore(current.proxy_score), "proxy"),
scorePill("Current gold", formatScore(current.gold_score), "gold"),
);
if (next) {
pills.append(
scorePill("Next proxy change", finite(current.proxy_score) && finite(next.proxy_score) ? formatSigned(Number(next.proxy_score) - Number(current.proxy_score)) : "N/A", "proxy"),
scorePill("Next gold change", formatSigned(Number(next.gold_score) - Number(current.gold_score)), "gold"),
);
}
byId("current-response-title").textContent = `Round ${current.round ?? index}`;
byId("current-badges").replaceChildren(roundBadges(current));
const currentScores = responseScores(current, rounds[index - 1] || null);
currentScores.id = "current-scores";
document.querySelector(".current-pane .response-scores")?.replaceWith(currentScores);
renderStructured(byId("current-response"), current.candidate || current.response || "");
const nextPane = document.querySelector(".next-pane");
if (next) {
nextPane.classList.remove("empty");
byId("next-response-title").textContent = `Round ${next.round ?? index + 1}`;
byId("next-badges").replaceChildren(roundBadges(next));
const nextScores = responseScores(next, current);
nextScores.id = "next-scores";
document.querySelector(".next-pane .response-scores")?.replaceWith(nextScores);
renderStructured(byId("next-response"), next.candidate || next.response || "");
} else {
nextPane.classList.add("empty");
byId("next-response-title").textContent = "No subsequent round";
byId("next-badges").replaceChildren();
const emptyScores = document.createElement("div");
emptyScores.className = "response-scores";
emptyScores.id = "next-scores";
document.querySelector(".next-pane .response-scores")?.replaceWith(emptyScores);
renderStructured(byId("next-response"), "The configured round limit was reached, so this feedback did not produce another logged response.");
}
updateRoundControls(rounds.length);
}
function renderHistory(rounds) {
const body = byId("history-body");
body.replaceChildren();
rounds.forEach((round, index) => {
const row = document.createElement("tr");
if (index === state.activeRound) row.className = "active";
row.tabIndex = 0;
row.addEventListener("click", () => setActiveRound(index));
row.addEventListener("keydown", (event) => {
if (event.key === "Enter" || event.key === " ") setActiveRound(index);
});
const roundCell = document.createElement("td");
const roundButton = document.createElement("button");
roundButton.type = "button";
roundButton.textContent = `Round ${round.round ?? index}`;
roundCell.appendChild(roundButton);
const proxy = document.createElement("td");
proxy.className = "numeric proxy-value";
proxy.textContent = formatScore(round.proxy_score);
const gold = document.createElement("td");
gold.className = "numeric gold-value";
gold.textContent = formatScore(round.gold_score);
const changeValue = index ? Number(round.gold_score) - Number(rounds[index - 1].gold_score) : 0;
const change = document.createElement("td");
change.className = `numeric ${deltaClass(changeValue)}`.trim();
change.textContent = index ? formatSigned(changeValue) : "Initial";
const decision = document.createElement("td");
decision.textContent = [round.decision, round.preference].filter(Boolean).join(" · ") || "N/A";
const selection = document.createElement("td");
selection.textContent = round.selected_final
? `Returned${Number(round.selection_weight || 0) < 1 ? ` · weight ${formatScore(round.selection_weight, 3)}` : ""}`
: Number(round.selection_weight || 0) > 0
? `Tie weight ${formatScore(round.selection_weight, 3)}`
: "";
const feedback = document.createElement("td");
feedback.className = "feedback-preview";
feedback.textContent = round.feedback_used || round.feedback || (round.proxy_valid ? "" : FALLBACK_FEEDBACK);
row.append(roundCell, proxy, gold, change, decision, selection, feedback);
body.appendChild(row);
});
}
function toggleClamp(button, content) {
const expanded = button.getAttribute("aria-expanded") === "true";
button.setAttribute("aria-expanded", String(!expanded));
content.classList.toggle("is-clamped", expanded);
button.textContent = expanded ? button.dataset.collapsedLabel : button.dataset.expandedLabel;
}
function switchView(view) {
state.view = view;
document.querySelectorAll(".tab").forEach((tab) => {
const active = tab.dataset.view === view;
tab.classList.toggle("active", active);
tab.setAttribute("aria-selected", String(active));
});
byId("trajectory-view").hidden = view !== "trajectory";
byId("overview-view").hidden = view !== "overview";
if (view === "overview") renderOverview();
}
function summaryMetric(summary, ...names) {
for (const name of names) if (summary && summary[name] !== undefined) return summary[name];
return null;
}
function renderOverview() {
const summary = state.index.summary || {};
const records = state.trajectories;
const initial = summaryMetric(summary, "initial_gold_mean") ?? mean(records.map((row) => row.initial_gold));
const selected = summaryMetric(summary, "selected_gold_mean") ?? mean(records.map((row) => row.selected_gold));
const last = summaryMetric(summary, "last_gold_mean") ?? mean(records.map((row) => row.last_gold));
const best = summaryMetric(summary, "best_gold_mean", "oracle_best_gold_mean") ?? mean(records.map((row) => row.best_gold));
const spearman = summaryMetric(summary, "proxy_gold_spearman_mean", "mean_proxy_gold_spearman") ?? mean(records.map((row) => row.proxy_gold_spearman));
const overview = byId("overview-summary");
overview.replaceChildren(
metricCell("Initial gold mean", formatScore(initial), `${records.length} paths`, "gold"),
metricCell("Selected gold mean", formatScore(selected), "tie-weighted", "gold"),
metricCell("Selected change", formatSigned(finite(selected) && finite(initial) ? Number(selected) - Number(initial) : null), "vs initial", deltaClass(finite(selected) && finite(initial) ? Number(selected) - Number(initial) : null)),
metricCell("Last gold mean", formatScore(last), "round 8", "gold"),
metricCell("Oracle best mean", formatScore(best), "best state per path", "gold"),
metricCell("Mean rank agreement", formatScore(spearman), "trajectory Spearman", "proxy"),
);
renderOutcomeChart(summary);
renderRoundChart(summary.per_round || summary.rounds || []);
renderCheckpointTable();
}
function renderOutcomeChart(summary) {
const supplied = summary.outcome_counts || {};
const counts = {
improved: Number(supplied.improved ?? state.trajectories.filter((row) => row.outcome === "improved").length),
unchanged: Number(supplied.unchanged ?? state.trajectories.filter((row) => row.outcome === "unchanged").length),
worsened: Number(supplied.worsened ?? state.trajectories.filter((row) => row.outcome === "worsened").length),
};
const total = Object.values(counts).reduce((sum, value) => sum + value, 0) || 1;
const container = byId("outcome-chart");
container.replaceChildren();
const bar = document.createElement("div");
bar.className = "outcome-bar";
Object.entries(counts).forEach(([name, count]) => {
const segment = document.createElement("div");
segment.className = `outcome-segment ${name}`;
segment.style.width = `${(count / total) * 100}%`;
const label = document.createElement("span");
label.textContent = `${name} ${count}`;
segment.appendChild(label);
segment.title = `${name}: ${count} (${formatPercent(count / total)})`;
bar.appendChild(segment);
});
const legend = document.createElement("div");
legend.className = "outcome-legend";
Object.entries(counts).forEach(([name, count]) => {
const item = document.createElement("span");
item.append(document.createTextNode(`${name[0].toUpperCase()}${name.slice(1)}`));
const strong = document.createElement("strong");
strong.textContent = `${count} · ${formatPercent(count / total)}`;
item.appendChild(strong);
legend.appendChild(item);
});
container.append(bar, legend);
}
function svgElement(name, attributes = {}) {
const element = document.createElementNS("http://www.w3.org/2000/svg", name);
Object.entries(attributes).forEach(([key, value]) => element.setAttribute(key, String(value)));
return element;
}
function renderRoundChart(rows) {
const container = byId("round-chart");
container.replaceChildren();
if (!rows.length) {
const empty = document.createElement("p");
empty.textContent = "Per-round aggregates were not exported.";
container.appendChild(empty);
return;
}
const width = 1000;
const height = 310;
const left = 54;
const right = 24;
const top = 20;
const bottom = 42;
const plotWidth = width - left - right;
const plotHeight = height - top - bottom;
const x = (index) => left + (rows.length === 1 ? 0 : (index / (rows.length - 1)) * plotWidth);
const y = (value) => top + (1 - Math.max(0, Math.min(1, Number(value)))) * plotHeight;
const svg = svgElement("svg", { viewBox: `0 0 ${width} ${height}`, role: "img", "aria-label": "Mean proxy and gold scores by feedback round" });
[0, 0.25, 0.5, 0.75, 1].forEach((value) => {
svg.appendChild(svgElement("line", { x1: left, y1: y(value), x2: width - right, y2: y(value), class: "chart-grid" }));
const label = svgElement("text", { x: left - 10, y: y(value) + 4, "text-anchor": "end", class: "chart-axis-label" });
label.textContent = value.toFixed(2);
svg.appendChild(label);
});
rows.forEach((row, index) => {
const label = svgElement("text", { x: x(index), y: height - 16, "text-anchor": "middle", class: "chart-axis-label" });
label.textContent = `Round ${row.round ?? index}`;
svg.appendChild(label);
});
const proxyValues = rows.map((row) => number(row.proxy_mean ?? row.mean_proxy));
const goldValues = rows.map((row) => number(row.gold_mean ?? row.mean_gold));
const makePath = (values) => values.map((value, index) => `${index ? "L" : "M"} ${x(index)} ${y(value)}`).join(" ");
if (proxyValues.every(finite)) svg.appendChild(svgElement("path", { d: makePath(proxyValues), class: "chart-proxy" }));
if (goldValues.every(finite)) svg.appendChild(svgElement("path", { d: makePath(goldValues), class: "chart-gold" }));
proxyValues.forEach((value, index) => {
if (!finite(value)) return;
const dot = svgElement("circle", { cx: x(index), cy: y(value), r: 4, class: "chart-dot-proxy" });
const title = svgElement("title");
title.textContent = `Round ${rows[index].round ?? index}: proxy ${formatScore(value)}`;
dot.appendChild(title);
svg.appendChild(dot);
});
goldValues.forEach((value, index) => {
if (!finite(value)) return;
const dot = svgElement("circle", { cx: x(index), cy: y(value), r: 4, class: "chart-dot-gold" });
const title = svgElement("title");
title.textContent = `Round ${rows[index].round ?? index}: gold ${formatScore(value)}`;
dot.appendChild(title);
svg.appendChild(dot);
});
container.appendChild(svg);
}
function checkpointStatistics(checkpoint) {
const records = state.trajectories.filter((record) => checkpointId(record) === checkpoint.id);
return {
count: records.length,
initial: checkpoint.initial_gold_mean ?? mean(records.map((row) => row.initial_gold)),
selected: checkpoint.selected_gold_mean ?? mean(records.map((row) => row.selected_gold)),
best: checkpoint.best_gold_mean ?? checkpoint.oracle_best_gold_mean ?? mean(records.map((row) => row.best_gold)),
};
}
function renderCheckpointTable() {
const body = byId("checkpoint-body");
body.replaceChildren();
state.checkpoints.forEach((checkpoint) => {
const stats = checkpointStatistics(checkpoint);
const row = document.createElement("tr");
row.addEventListener("click", () => {
byId("checkpoint-select").value = checkpoint.id;
applyTrajectoryFilter();
switchView("trajectory");
loadSelectedTrajectory();
});
const cells = [
checkpoint.step,
checkpoint.title || checkpoint.context_label || checkpoint.uid,
stats.count,
formatScore(stats.initial),
formatScore(stats.selected),
formatScore(stats.best),
];
cells.forEach((value, index) => {
const cell = document.createElement("td");
cell.textContent = String(value ?? "N/A");
if (index >= 2) cell.className = "numeric";
row.appendChild(cell);
});
body.appendChild(row);
});
}
function moveTrajectory(offset) {
const current = state.visible.findIndex((record) => trajectoryId(record) === byId("trajectory-select").value);
const next = Math.max(0, Math.min(current + offset, state.visible.length - 1));
if (next === current || !state.visible[next]) return;
byId("trajectory-select").value = trajectoryId(state.visible[next]);
loadSelectedTrajectory();
}
function refreshIcons() {
if (window.lucide && typeof window.lucide.createIcons === "function") window.lucide.createIcons();
}
function bindEvents() {
document.querySelectorAll(".tab").forEach((tab) => tab.addEventListener("click", () => switchView(tab.dataset.view)));
byId("checkpoint-select").addEventListener("change", () => {
applyTrajectoryFilter();
loadSelectedTrajectory();
});
byId("outcome-select").addEventListener("change", () => {
applyTrajectoryFilter();
loadSelectedTrajectory();
});
byId("trajectory-select").addEventListener("change", loadSelectedTrajectory);
byId("previous-trajectory").addEventListener("click", () => moveTrajectory(-1));
byId("next-trajectory").addEventListener("click", () => moveTrajectory(1));
byId("previous-round").addEventListener("click", () => setActiveRound(state.activeRound - 1));
byId("next-round").addEventListener("click", () => setActiveRound(state.activeRound + 1));
byId("context-toggle").addEventListener("click", () => toggleClamp(byId("context-toggle"), byId("context-text")));
byId("rubric-toggle").addEventListener("click", () => toggleClamp(byId("rubric-toggle"), byId("rubric-text")));
document.addEventListener("keydown", (event) => {
if (state.view !== "trajectory" || ["INPUT", "SELECT", "TEXTAREA", "SUMMARY"].includes(document.activeElement?.tagName)) return;
if (event.key === "ArrowLeft") setActiveRound(state.activeRound - 1);
if (event.key === "ArrowRight") setActiveRound(state.activeRound + 1);
});
}
async function initialize() {
bindEvents();
refreshIcons();
try {
const response = await fetch("data/index.json");
if (!response.ok) throw new Error(`HTTP ${response.status}`);
state.index = await response.json();
state.trajectories = state.index.trajectories || state.index.records || [];
if (!state.trajectories.length) throw new Error("the snapshot contains no trajectories");
byId("page-title").textContent = state.index.title || "Feedback trajectories";
byId("strategy-label").textContent = state.index.strategy || "self_reflection_best";
const counts = state.index.counts || {};
byId("dataset-count").textContent = `${counts.trajectories || state.trajectories.length} trajectories · ${counts.checkpoints || new Set(state.trajectories.map(checkpointId)).size} checkpoint examples`;
buildCheckpointIndex();
populateCheckpointSelect();
applyTrajectoryFilter();
renderOverview();
await loadSelectedTrajectory();
} catch (error) {
showError(`Could not load the feedback snapshot (${error.message}).`);
}
}
initialize();