From cecb3531c4c9b44a9647a8508a44c3cf3168134c Mon Sep 17 00:00:00 2001 From: Florent Tapponnier <160007691+Flotapponnier@users.noreply.github.com> Date: Wed, 29 Jul 2026 19:45:09 +0200 Subject: [PATCH 1/3] fix(kalshi-res): skip KXMV* in pollClosed (6s closed window race) --- .../pm-resolution-delay/cmd/script/kalshi_resolution.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/harnesses/pm-resolution-delay/cmd/script/kalshi_resolution.go b/harnesses/pm-resolution-delay/cmd/script/kalshi_resolution.go index f3d98c26..da70ef2a 100644 --- a/harnesses/pm-resolution-delay/cmd/script/kalshi_resolution.go +++ b/harnesses/pm-resolution-delay/cmd/script/kalshi_resolution.go @@ -183,6 +183,11 @@ func (k *kalshiTracker) pollClosed() { k.mu.Lock() defer k.mu.Unlock() for _, m := range markets { + // KXMV* = auto-generated multivariate parlays. They can briefly pass + // through status=closed (6-10s window) before auto-settling. Exclude. + if strings.HasPrefix(m.Ticker, "KXMV") { + continue + } ct, err := time.Parse(time.RFC3339, m.CloseTime) if err != nil { continue From d70f1084a5664db161bda9037527b52934167cd1 Mon Sep 17 00:00:00 2001 From: Florent Tapponnier <160007691+Flotapponnier@users.noreply.github.com> Date: Wed, 29 Jul 2026 19:46:20 +0200 Subject: [PATCH 2/3] fix: update Wikidata Q ID to Q140756438 (Q140172649 deleted) --- src/app/layout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 04f21faa..3fe4b286 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -147,7 +147,7 @@ const ORG_JSONLD = { // Wikidata entity: anchors the OpenChainBench brand in the // Knowledge Graph so the brand query resolves to this domain // instead of the unrelated "OpenBench" homonyms. - "https://www.wikidata.org/wiki/Q140172649", + "https://www.wikidata.org/wiki/Q140756438", ], }, { From 2b490671e47cb37bab42ba7723aa1e05fca107db Mon Sep 17 00:00:00 2001 From: Florent Tapponnier <160007691+Flotapponnier@users.noreply.github.com> Date: Wed, 29 Jul 2026 19:46:29 +0200 Subject: [PATCH 3/3] =?UTF-8?q?fix:=207D/30D=20chart=20shows=200.0s=20?= =?UTF-8?q?=E2=80=94=20add=20raw=3D1=20to=20bypass=20display=20unit=20conv?= =?UTF-8?q?ersion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/api/series/[slug]/route.ts | 26 +++++++++++++++------- src/components/time-series-chart/index.tsx | 6 ++--- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/app/api/series/[slug]/route.ts b/src/app/api/series/[slug]/route.ts index f247e535..371358ff 100644 --- a/src/app/api/series/[slug]/route.ts +++ b/src/app/api/series/[slug]/route.ts @@ -183,6 +183,12 @@ export async function GET( } const url = new URL(req.url); + // When ?raw=1 the response values stay in OCB's internal unit convention + // (milliseconds for "s" benches, basis points for "bps" benches) so the + // time-series chart can pass them directly to fmtUnit without a second + // division. The video renderer omits raw=1 and gets the display-friendly + // conversion (seconds / percent) it expects. + const rawMode = url.searchParams.get("raw") === "1"; const rangeParam = url.searchParams.get("range") ?? "24h"; if (!isRangeKey(rangeParam)) { return NextResponse.json( @@ -330,16 +336,20 @@ export async function GET( // "bps" = stored in basis points, site displays as % (÷100) → send "pct" + divide values // "s" = stored in milliseconds, site displays as seconds → send "s" + divide values // "pct", "bp", "usd", "count", … → pass through unchanged + // When ?raw=1 (time-series chart), skip conversion so fmtUnit receives + // values in the same internal unit as the 24h series from the bench object. let displayUnit = sourceUnit; const providers = rawProviders.map((p) => ({ ...p })); - if (sourceUnit === "bps") { - displayUnit = "pct"; - for (const p of providers) { - p.values = p.values.map((v) => (v == null ? null : v / 100)); - } - } else if (sourceUnit === "s") { - for (const p of providers) { - p.values = p.values.map((v) => (v == null ? null : v / 1000)); + if (!rawMode) { + if (sourceUnit === "bps") { + displayUnit = "pct"; + for (const p of providers) { + p.values = p.values.map((v) => (v == null ? null : v / 100)); + } + } else if (sourceUnit === "s") { + for (const p of providers) { + p.values = p.values.map((v) => (v == null ? null : v / 1000)); + } } } diff --git a/src/components/time-series-chart/index.tsx b/src/components/time-series-chart/index.tsx index c2e7fcb8..a510f3b3 100644 --- a/src/components/time-series-chart/index.tsx +++ b/src/components/time-series-chart/index.tsx @@ -186,7 +186,7 @@ export function TimeSeriesChart({ // never refetched. const done: Record<"7d" | "30d", boolean> = { "7d": false, "30d": false }; const buildQs = (range: "7d" | "30d") => { - const qs = new URLSearchParams({ range }); + const qs = new URLSearchParams({ range, raw: "1" }); if (regionProp && regionProp !== "all") qs.set("region", regionProp); if (chainProp && chainProp !== "all") qs.set("chain", chainProp); return qs.toString(); @@ -243,7 +243,7 @@ export function TimeSeriesChart({ "30d": !need30d, }; const buildQs = (range: "7d" | "30d") => { - const qs = new URLSearchParams({ range, panel: activePanelId }); + const qs = new URLSearchParams({ range, panel: activePanelId, raw: "1" }); if (regionProp && regionProp !== "all") qs.set("region", regionProp); if (chainProp && chainProp !== "all") qs.set("chain", chainProp); return qs.toString(); @@ -299,7 +299,7 @@ export function TimeSeriesChart({ if (!need90d && !need1y) return; let cancelled = false; const buildQs = (r: "90d" | "1y") => { - const qs = new URLSearchParams({ range: r, panel: activePanelId }); + const qs = new URLSearchParams({ range: r, panel: activePanelId, raw: "1" }); if (regionProp && regionProp !== "all") qs.set("region", regionProp); if (chainProp && chainProp !== "all") qs.set("chain", chainProp); return qs.toString();