fix: Sem. préc. HEAD→GET, prevMeetings cache, remove footer

- investinglive: tryUrl HEAD→GET + res.body?.cancel() (WordPress bloque HEAD)
  fenêtre recherche article préc. élargie 21→28 jours
- rateprobability: CBRatePath + prevMeetings/prevWeekDate, loadPrevWeekCachedBody()
  fetchAllCBPaths enrichit prevMeetings depuis snapshot GitHub Actions
- fetch-rate-data.mjs: rotation current→previousWeek (5–9 jours) pour Rate Curve
- CurrencyCard: rateCurveData préfère prevMeetings (exact/meeting) > ilDelta (approx)
  légende hasPrevCurve pilote affichage ligne bleue et label date
- page.tsx: suppression footer Sources/LLM, remplacement par pb-12

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
caty21
2026-06-27 19:40:48 +02:00
co-authored by Claude Sonnet 4.6
parent 1a7468d718
commit a978f19088
5 changed files with 82 additions and 25 deletions
+7 -4
View File
@@ -52,12 +52,15 @@ async function tryUrl(daysAgo: number): Promise<ArticleRef | null> {
const dateStr = `${yyyymmdd.slice(0,4)}-${yyyymmdd.slice(4,6)}-${yyyymmdd.slice(6,8)}`;
const url = `https://investinglive.com/news/how-have-interest-rate-expectations-changed-after-this-weeks-event-${yyyymmdd}/`;
try {
// GET au lieu de HEAD — certains serveurs WordPress refusent HEAD (405/404 même si la page existe)
const res = await fetch(url, {
method: "HEAD",
method: "GET",
headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/124.0.0.0 Safari/537.36" },
cache: "no-store",
});
return res.ok ? { url, dateStr, daysAgo } : null;
if (!res.ok) return null;
await res.body?.cancel(); // libère la connexion sans télécharger le body
return { url, dateStr, daysAgo };
} catch { return null; }
}
@@ -73,8 +76,8 @@ async function findArticleRefs(): Promise<{ current: ArticleRef | null; previous
if (!current) return { current: null, previous: null };
let previous: ArticleRef | null = null;
// Start the day after the current article and look up to 21 days further back
for (let d = current.daysAgo + 1; d <= current.daysAgo + 21; d++) {
// Start the day after the current article and look up to 28 days further back
for (let d = current.daysAgo + 1; d <= current.daysAgo + 28; d++) {
const found = await tryUrl(d);
if (found) { previous = found; break; }
}
+29
View File
@@ -44,6 +44,8 @@ export interface CBRatePath {
yearEndImplied: number | null; // taux impliqué à la dernière réunion connue (SOFR)
ilCurrent?: ILCurrent; // valeurs absolues de l'article IL courant
ilDelta?: ILWeeklyDelta; // delta vs article IL semaine précédente
prevMeetings?: RateProbMeeting[]; // réunions semaine précédente (snapshot RP)
prevWeekDate?: string; // date du snapshot semaine précédente
}
export type RateProbData = Partial<Record<Currency, CBRatePath>>;
@@ -244,6 +246,21 @@ function loadCachedRPBody(ccy: string, slug: string): Record<string, unknown> |
} catch { return null; }
}
function loadPrevWeekCachedBody(ccy: string): { body: Record<string, unknown>; date: string } | null {
try {
const filePath = join(process.cwd(), "data", "rate-probabilities.json");
const raw = readFileSync(filePath, "utf8");
const parsed = JSON.parse(raw) as { previousWeek?: Record<string, unknown>; previousWeekFetchedAt?: string };
if (!parsed.previousWeek || !parsed.previousWeekFetchedAt) return null;
const entry = parsed.previousWeek[ccy] as Record<string, unknown> | undefined;
if (!entry) return null;
const ageMs = Date.now() - new Date(parsed.previousWeekFetchedAt).getTime();
// Le snapshot semaine précédente doit dater de 4 à 10 jours
if (ageMs < 3 * 86400000 || ageMs > 11 * 86400000) return null;
return { body: entry, date: parsed.previousWeekFetchedAt.slice(0, 10) };
} catch { return null; }
}
// Reparse un body brut de rateprobability.com (même format que fetchCBPath)
function parseCBBody(ccy: Currency, body: Record<string, unknown>): CBRatePath | null {
const today = body["today"] as Record<string, unknown> | undefined;
@@ -301,6 +318,18 @@ export async function fetchAllCBPaths(): Promise<RateProbData> {
}
}
// Enrichissement prevMeetings depuis snapshot semaine précédente (GitHub Actions)
for (const [ccy] of CB_KEYS) {
const path = data[ccy as Currency];
if (!path) continue;
const prev = loadPrevWeekCachedBody(ccy);
if (!prev) continue;
const prevPath = parseCBBody(ccy as Currency, prev.body);
if (prevPath?.meetings.length) {
data[ccy as Currency] = { ...path, prevMeetings: prevPath.meetings, prevWeekDate: prev.date };
}
}
// CHF/SNB : rateprobability ne couvre pas la SNB → InvestingLive est la seule source
if (!data["CHF"] && ilData["CHF"]) {
const snbPath = buildSNBPath(ilData, 0.00); // taux actuel SNB = 0%