Stop substituting synthetic market data when providers fail

- Replace synthetic fallback in getQuote()/getPriceHistory() with null returns
- Add QuoteResult/PriceHistoryResult types with { value, stale } structure
- Implement stale-while-revalidate: return cached value with stale=true on live fetch failure
- Cache failures for 30s to avoid hammering provider
- Update CompanyAnalysis type to use PriceData<T> wrapper
- Update task-processors to track failed/stale tickers explicitly
- Update price-history-card UI to show unavailable state and stale indicator
- Add comprehensive tests for failure cases
- Add e2e tests for null data, stale data, and live data scenarios

Resolves #14
This commit is contained in:
2026-03-14 23:37:12 -04:00
parent 5b68333a07
commit 529437c760
10 changed files with 496 additions and 230 deletions

View File

@@ -757,6 +757,11 @@ export type RecentDevelopments = {
weeklySnapshot: RecentDevelopmentsWeeklySnapshot | null;
};
export type PriceData<T> = {
value: T;
stale: boolean;
};
export type CompanyAnalysis = {
company: {
ticker: string;
@@ -766,10 +771,10 @@ export type CompanyAnalysis = {
tags: string[];
cik: string | null;
};
quote: number;
quote: PriceData<number | null>;
position: Holding | null;
priceHistory: Array<{ date: string; close: number }>;
benchmarkHistory: Array<{ date: string; close: number }>;
priceHistory: PriceData<Array<{ date: string; close: number }> | null>;
benchmarkHistory: PriceData<Array<{ date: string; close: number }> | null>;
financials: CompanyFinancialPoint[];
filings: Filing[];
aiReports: CompanyAiReport[];