From 40832be865266e9f5db17c402df56b583eee642d Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Sun, 1 Nov 2026 05:08:41 +0800 Subject: [PATCH] fix(console): name the history window when a range has no records A YTD scope whose stored native history starts in September read as a bare "Unavailable", which looks like a broken pipeline rather than a short history. The summary already publishes range_complete, period_from and requested_period_from, so state the shortfall window and keep every total withheld exactly as before. --- tests/console_display_gaps_validation.mjs | 32 ++++++++++++++++- .../frontend/src/api/contracts.ts | 5 +++ .../frontend/src/i18n/pages/performance.ts | 2 ++ .../src/pages/performance/SummaryCards.tsx | 20 +++++++++-- web/strategy-switch-console/v2_asset_map.js | 34 +++++++++---------- 5 files changed, 72 insertions(+), 21 deletions(-) diff --git a/tests/console_display_gaps_validation.mjs b/tests/console_display_gaps_validation.mjs index 0677fec6..3007529f 100644 --- a/tests/console_display_gaps_validation.mjs +++ b/tests/console_display_gaps_validation.mjs @@ -5,7 +5,7 @@ import { tmpdir } from "node:os"; import { join } from "node:path"; import { build } from "../web/strategy-switch-console/frontend/node_modules/esbuild/lib/main.js"; import { m0Subjects, healthStates, controlReasons, runtimeRecords } from "./fixtures/console-gaps.ts"; -import { formatDateTime } from "../web/strategy-switch-console/frontend/src/lib/format.ts"; +import { formatDateTime, formatDate } from "../web/strategy-switch-console/frontend/src/lib/format.ts"; // Render production components and dictionaries. Only network/hooks are replaced. const root = new URL("../web/strategy-switch-console/frontend/", import.meta.url).pathname; @@ -77,6 +77,36 @@ try { for (const [, value] of mainValues) assert.doesNotMatch(value.replace(/<[^>]*>/g, ""), /多币种|currenc/i, "reason must not become a main metric"); assert.equal((metrics.match(/class="metric-note(?:\s[^"]*)?"/g) || []).length, 1, "one shared metric explanation"); assert.doesNotMatch(metrics, /USD [0-9]|USDT [0-9]/, "mixed currencies never produce a combined amount"); + // A withheld total must name the date the store actually starts on, because + // "Unavailable" alone reads like a broken pipeline instead of a short history. + const shortHistory = coverageOverrides => ({ + status: "partial", unavailable_reason: "snapshot_history_missing", as_of: "2026-10-29", + currency: "USD", value_kind: "pnl", + coverage: { + account_aliases: ["tqqq"], currencies: ["USD"], cashflows: "complete", + period_from: "2026-09-25", period_to: "2026-10-29", requested_period_from: "2026-01-01", + range_complete: false, ...coverageOverrides, + }, + twr_return_percent: null, amount: null, simple_weighted_return_percent: null, + max_drawdown: { percent: null, peak_date: null, trough_date: null, unavailable_reason: "snapshot_history_missing" }, + excess_returns: [{ benchmark: "SPX", start: "2026-09-25", end: "2026-10-29", percentage_points: null, unavailable_reason: "snapshot_history_missing" }], + best_day: null, worst_day: null, + }); + globalThis.__displayState = { phase: "ready", data: shortHistory(), reload() {} }; + const short = ui.summary(language); + const shortNote = short.match(/