From 4f384f6f26fb6605854035018d9d8dc71f4d55d1 Mon Sep 17 00:00:00 2001 From: Maksim Kostromin Date: Thu, 29 Oct 2026 21:14:52 -0400 Subject: [PATCH] fix(updater): a short Yahoo chart never shrinks the published history The shared merge ran only when the Yahoo request had a period1 window, so with the default max a truncated Yahoo answer replaced the published history (2026-10-29: Franklin DVAL and USFI went from 999 rows to one). The merge now runs for every fresh chart; a full max answer starts at inception and comes back unchanged, one that does not join the published days counts as a failed chart and the fund is kept. --- scripts/update-data.test.ts | 7 +++++++ scripts/update-data.ts | 8 +++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/scripts/update-data.test.ts b/scripts/update-data.test.ts index e82889e0..acaee96c 100644 --- a/scripts/update-data.test.ts +++ b/scripts/update-data.test.ts @@ -1003,6 +1003,13 @@ describe('pipeline 7', () => { await s.run({ HISTORY_RANGE: '1y' }); expect(s.snapshot()).toEqual(first); expect(s.meta('AAA').history.totalRows).toBe(400); + // a truncated default-range (max) answer never shrinks the history either: one that joins the published days keeps them all, + // one of a new day that does not join keeps the fund as published + await s.run(); + expect(s.snapshot()).toEqual(first); + s.handler = (url, init) => (url.includes('finance.yahoo.com') ? new Response(JSON.stringify(chartPayload(1, Date.UTC(2026, 9, 25)))) : base(url, init)); + await s.run(); + expect(s.meta('AAA').history.totalRows).toBe(400); }); test('a relaxed guard still keeps numeric published weights from an all-blank N-PORT sheet (Q24)', async () => { diff --git a/scripts/update-data.ts b/scripts/update-data.ts index d4628467..4dd0f263 100755 --- a/scripts/update-data.ts +++ b/scripts/update-data.ts @@ -1797,11 +1797,13 @@ async function processFund(fund: CatalogFund, config: UpdaterConfig, previous: J const query = yahooChartQuery(config.historyRange); const payload = await fetchJson(`${YAHOO_CHART_URL}/${encodeURIComponent(fund.ticker)}?${query.toString()}`, `[ chart ] ${fund.ticker}`, config, { 'User-Agent': 'Mozilla/5.0' }); const fetched = parseChart(payload); - // A HISTORY_RANGE window never shrinks the published history (and with it 3y, 5y, 10y and since inception); the published + // A fresh chart never shrinks the published history (and with it 3y, 5y, 10y and since inception): a HISTORY_RANGE window, and + // also a truncated `max` answer (2026-10-29: Yahoo returned 2 bars for Franklin DVAL and USFI). A full `max` answer starts at + // inception: nothing older, unchanged. The published // distributions table is [Ex-Date, ..., Total Distribution], the window merge reads [date, amount] const publishedDistributions = (Array.isArray(previousMeta?.distributions?.rows) ? previousMeta.distributions.rows : []).map((cells: unknown) => (Array.isArray(cells) ? [cells[0], cells[cells.length - 1]] : cells)); - chart = Number(query.get('period1')) > 0 ? mergeWindowedChart(fetched, previousRows, publishedDistributions) : fetched; - if (!chart) throw new Error(`chart window does not join the published history (${config.historyRange})`); + chart = mergeWindowedChart(fetched, previousRows, publishedDistributions); + if (!chart) throw new Error(`chart does not join the published history (${config.historyRange}, ${fetched.days.length} days)`); days = chart.days; fresh = fresh || days.length > 0; } catch (error) {