Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions apps/web/src/pages/mission-control-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -249,16 +249,21 @@ export function MissionControlRoute({

const days =
insightsActivity.kind === "ready" ? insightsActivity.data.days : [];
const insightsReady = insightsActivity.kind === "ready";
const todayKey = new Date().toISOString().slice(0, 10);
const today = days.find((day) => day.day === todayKey) ?? null;
const priorDays = days.filter((day) => day.day !== todayKey);
const avgTurns =
priorDays.length > 0
? priorDays.reduce((sum, day) => sum + day.turns, 0) / priorDays.length
: null;
const todaySpend =
today === null
? null
// Ready but no today row means zero activity today, not "unknown". Dash
// only while the activity query is still settling (or cost rates unknown).
const runsToday = insightsReady ? (today?.turns ?? 0) : null;
const todaySpend = !insightsReady
? null
: today === null
? 0
: today.byModel.some((model) => model.costUsd === null)
? null
: today.byModel.reduce((sum, model) => sum + (model.costUsd ?? 0), 0);
Expand Down Expand Up @@ -302,15 +307,17 @@ export function MissionControlRoute({
/>
<StatGridItem
label="Runs today"
value={dash(today === null ? null : today.turns)}
value={dash(runsToday)}
sub={
avgTurns !== null ? `avg ${Math.round(avgTurns)}/day` : "—"
avgTurns !== null
? `avg ${Math.round(avgTurns)}/day`
: "quiet so far"
}
/>
<StatGridItem
label="Spend today"
value={formatUsd(todaySpend)}
sub="7-day activity"
sub="so far today"
/>
</StatGrid>

Expand Down
70 changes: 70 additions & 0 deletions apps/web/test/mission-control-page.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,76 @@ describe("MissionControlRoute", () => {
expect(container.textContent).toContain("Nothing recent yet.");
});

test("ready activity with no today row shows 0 / $0.00, not double em-dash (CL-6798)", async () => {
stubEmptyBenchFetch();
container = document.createElement("div");
document.body.appendChild(container);
root = createRoot(container);
await act(async () => {
root?.render(
<TestQueryProvider>
<NavigationProvider navigate={() => undefined}>
<BenchContext.Provider value={benchState}>
<MissionControlRoute navigate={() => undefined} />
</BenchContext.Provider>
</NavigationProvider>
</TestQueryProvider>,
);
});
for (let count = 0; count < 5; count += 1) {
await act(async () => {
await new Promise((resolve) => setTimeout(resolve, 0));
});
}
const text = container.textContent ?? "";
// Ready + missing today is zero, not unknown — one empty treatment, not
// value em-dash stacked on sub em-dash.
expect(text).toContain("Runs today");
expect(text).not.toMatch(/Runs today—/);
expect(text).toMatch(/Runs today0/);
expect(text).toContain("Spend today");
expect(text).toContain("$0.00");
expect(text).not.toContain("7-day activity");
expect(text).toContain("so far today");
});

test("Spend today keeps em-dash when today's cost rate is unknown (CL-6798)", async () => {
const todayKey = new Date().toISOString().slice(0, 10);
stubBenchFetchWithActivity([
{
day: todayKey,
turns: 3,
tokens: 50,
byModel: [{ model: "m", tokens: 50, costUsd: null }],
},
]);
container = document.createElement("div");
document.body.appendChild(container);
root = createRoot(container);
await act(async () => {
root?.render(
<TestQueryProvider>
<NavigationProvider navigate={() => undefined}>
<BenchContext.Provider value={benchState}>
<MissionControlRoute navigate={() => undefined} />
</BenchContext.Provider>
</NavigationProvider>
</TestQueryProvider>,
);
});
for (let count = 0; count < 5; count += 1) {
await act(async () => {
await new Promise((resolve) => setTimeout(resolve, 0));
});
}
const text = container.textContent ?? "";
expect(text).toMatch(/Runs today3/);
expect(text).toContain("so far today");
expect(text).not.toContain("7-day activity");
// Cost unknown → em-dash for spend value; subcopy still names today.
expect(text).toMatch(/Spend today—so far today/);
});

test("This week's run count includes today, so it is never less than runs today (CL-6667)", async () => {
const todayKey = new Date().toISOString().slice(0, 10);
const yesterdayKey = new Date(Date.now() - 24 * 60 * 60 * 1000)
Expand Down
Loading