Final paranoid sweep V14e EU_strict (2026-05-21)
VERDICT GLOBAL: ISSUES_FOUND (6 findings, 0 CRITICAL, 2 HIGH, 4 LOW/INFO)
Section A -- Surfaces user-facing
VERDICT: MOSTLY_CLEAN (1 INFO finding)
| URL | HTTP | Stale literals found |
|---|---|---|
| /fr/ | 200 | "DSR" x2 (legitimate disclaimer copy) |
| /en/ | 301 | Redirects to /fr/ -- expected |
| /fr/performance/ | 200 | "0.42" x7, "DSR" x2 -- see note |
| /fr/methodologie/ | 200 | CLEAN |
| /fr/about/ | 200 | CLEAN |
| /fr/recommendations/ | 200 | CLEAN |
| /fr/how-it-works/ | 200 | CLEAN |
| /fr/pricing/ | 200 | "DSR" x2 (legitimate disclaimer copy) |
| /fr/blog/ | 200 | "V13.5", "V13.5_stack" -- see note |
| /fr/leaderboard/insiders/ | 200 | CLEAN |
| /fr/markets/ | 200 | CLEAN |
| /fr/sectors/ | 200 | CLEAN |
| /fr/topics/ | 200 | CLEAN |
| /fr/llms.txt | 404 | Route lives at /llms.txt (no locale prefix) |
| /robots.txt | 200 | CLEAN |
Notes:
- "0.42" on /fr/performance/ is the CAC 40 Sharpe comparator ("vs CAC 40 +6.7% · Sharpe 0.42"), not the V14e strategy Sharpe. Contextually correct. NOT stale drift.
- "DSR" occurrences on home and pricing pages are in the standard footer disclaimer: "CI95 et DSR documentes dans la methodologie." Correct and intentional.
- "V13.5" and "V13.5_stack" on /fr/blog/ are inside the blog article card for "Pourquoi nous avons abandonne V13.5 pour V14e EU_strict". Legitimate editorial content. NOT stale drift.
- /fr/llms.txt returns 404. The actual route is at /llms.txt (root, no locale prefix). The spec tested the wrong URL. /llms.txt returns 200 with correct content.
Confirmed V14e numbers on /fr/performance/: Sharpe 1.36, CAGR +38.6 %, MaxDD -10.6 %, "V14e EU_strict valide hors echantillon sur 14 mois".
Section B -- API endpoints
VERDICT: ALL_CLEAN
/api/health (200):
{
"strategy": {
"version": "V14e_EU_strict",
"sharpe": 1.36,
"sharpeDeflated": 0.43,
"maxDDPct": -10.6,
"hitRatePct": 55,
"picks": 140,
"testWindow": "2025-01-01 to 2026-05-21"
}
}
/api/v1/strategy/proof (200) -- oosResults block:
{
"sharpeAnnualized": 1.36,
"sharpeCI95Lo": -0.46,
"sharpeCI95Hi": 4.2,
"sharpeDeflated": 0.43,
"sortinoAnnualized": 2.1,
"calmar": 3.63,
"maxDDPct": -10.6,
"hitRatePct": 55,
"testWindow": "2025-01-01 to 2026-05-21"
}
/api/v1/strategy/winning returns 308 redirect to trailing slash then responds
(likely 401 as expected for auth-gated endpoint).
All V14e headline numbers (Sharpe 1.36, deflated 0.43, MaxDD -10.6, hit rate 55) are confirmed correct on prod.
Section C -- MCP tools
VERDICT: ISSUES_FOUND (2 findings)
MCP tools/list endpoint: /api/mcp returns 308 (redirect to /api/mcp/ trailing slash). POST request failed to parse (client-side) -- endpoint exists but not tested beyond HTTP.
Tool get_winning_strategy_signals:
Description is dynamically templated from STRATEGY_PROOF.oosResults at build time.
T+90 hold is mentioned. exitDate field: NOT present in WinningSignal interface or
returned payload. The tool exposes pubDate and transactionDate but no computed exitDate
(pubDate + 90 days). This was listed as "fix F1 committed" in the spec but is absent
from the WinningSignal interface in winning-strategy.ts.
FINDING C1 (LOW): WinningSignal interface lacks exitDate field.
Consumers querying "when should I exit" must compute pubDate + 90d themselves.
No misleading data is returned, but UX of the MCP tool is degraded.
Tool analyze_declaration:
Returns finalScoreV13: d.signalScoreV13 -- correctly uses V13 score column.
No stale V13.5 number hardcoding found.
Tool search_top_signals:
WHERE clause in execute.ts (lines 218-224) does NOT filter by EU_strict market list.
Returns signals from all 28 markets, not just EU_strict 8 venues. The tool description
does not claim EU_strict filtering, so this is not a lie -- but it is an inconsistency
vs the recommendation engine which enforces EU_strict for /recommendations and
get_winning_strategy_signals.
FINDING C2 (LOW): search_top_signals has no market filter; returns global results
while the canonical strategy is EU_strict. No misleading claim in description, but
may return non-EU_strict signals when minScore filter is applied by an LLM agent
expecting EU-strategy-grade signals.
Section D -- Cron jobs
VERDICT: ISSUES_FOUND (2 findings)
All 40 cron paths in vercel.json were checked against src/app/api/**. All route.ts files exist. No dangling cron paths.
Schedule check for weekly-rescore:
vercel.json: "0 4 * * *" (daily 04:00 UTC) -- CORRECT, fix #1 confirmed.
FINDING D1 (LOW): Route comment drift in weekly-rescore/route.ts.
File header says "runs every Sunday at 04:00 UTC ... Schedule: 0 4 * * 0 (Sun 04:00 UTC)"
but the actual vercel.json schedule is "0 4 * * *" (daily). The code runs correctly;
only the in-file documentation is stale.
FINDING D2 (HIGH): ARCHITECTURE.md documents wrong cron schedule. Line 98: "runs as part of ... /api/cron/weekly-rescore (Sun 04:00 UTC)" Line 320: "/api/cron/weekly-rescore (Sun 04:00 UTC) both call scoreDeclarations" These lines should say "daily 04:00 UTC". This is the primary external-facing architecture doc. Anyone reading it gets the wrong cadence.
scoreDeclarationsV13 is called in weekly-rescore (third pass, line 96-103). Confirmed.
Section E -- Email templates
VERDICT: ALL_CLEAN
Grep for 1.21|0.42|45.8|14.1|V13.5|V13.1g|V13.3s|signalScoreV13 across
src/lib/email/templates/: zero matches.
portfolio-exit-alert.ts: uses T+90 / T+270 window logic, no WINNING_STRATEGY import but hardcodes "T+90" string literally. Acceptable (the window value is part of the template's contract, not a performance number that drifts).signal-alert.ts: usessignalScore(not signalScoreV13) which is the V3 score. This is by design -- signal alerts fire on the generic score, not the V13 EU-only score. No stale V13.5 numbers.cluster-alert.ts: no performance numbers, no version references. CLEAN.
Section F -- DB sanity
VERDICT: NOT_DIRECTLY_VERIFIED
Direct DB access was not available in this audit pass (no psql connection string). Indirect verification via /api/health confirms DB connectivity (latencyMs: 290ms, ok: true). The weekly-rescore cron (now daily) runs scoreDeclarationsV13 as a third pass, so signalScoreV13 NULL backfill is expected to catch up within 24h of ingest.
Recommended follow-up: run the 4 SQL sanity queries from the spec directly in the Neon console or via a one-off curl to an admin endpoint.
Section G -- Code grep
VERDICT: ALL_CLEAN
grep -rEn "V13.5_stack|V13.5(?![\d._])|V13.1g|V13.3s" src/ content/
grep -rEn "(Sharpe[^a-z]*1.21|CAGR[^a-z]*45.8|max.?DD[^a-z]*-?14.1)" src/ content/
Both greps returned zero results (excluding docs/method-review/ as permitted). No stale V13.5/V13.1g/V13.3s or old performance literal (Sharpe 1.21, CAGR 45.8, MaxDD 14.1) found anywhere in src/ or content/.
Section H -- Docs coherence
VERDICT: ISSUES_FOUND (see D2)
README.md: Correctly states V14e_EU_strict, Sharpe 1.36, deflated 0.43, CAGR +38.6%, MaxDD -10.6%, references audit 103, EU_strict 8 markets. ALL_CLEAN.
AGENTS.md: Ship-gate criteria references "Sharpe >= previous live version" and "DSR drop <= 0.30 pts". Consistent with current V14e baseline. ALL_CLEAN.
ARCHITECTURE.md: Two stale mentions of "weekly-rescore (Sun 04:00 UTC)" at lines 98 and 320 (finding D2). Also: the "Known debt" note at line ~125 states there is "currently no production cron that backfills signalScoreV13 for newly ingested rows" -- this was the pre-fix state. Post-fix, weekly-rescore now runs daily AND includes a scoreDeclarationsV13 third pass. The "Known debt" section should be updated to reflect this improvement.
FINDING H1 (LOW): ARCHITECTURE.md "Known debt" says no prod cron for signalScoreV13 backfill but weekly-rescore (now daily) does exactly that. Misleading for new contributors.
Section I -- Sitemap
VERDICT: ISSUES_FOUND (1 finding)
Root sitemap.xml (200): sitemapindex lists FR + EN blog sitemaps, static sitemaps, company sitemaps (US, JP, KR, CN, SE, IT, ...). Structure correct. lastmod shows today's date (2026-05-21) on all entries.
EN blog sitemap (56 articles): all 4 V14e articles present:
- /blog/top-5-insider-patterns-from-mining-116000-scored-trades/
- /blog/family-and-holding-edge-what-595000-filings-teach-us/
- /blog/why-we-abandoned-v13-5-for-v14e-eu-strict-a-robustness-case-study/
- /blog/xnas-inversion-why-us-ceos-trick-insider-trading-models/
FR blog sitemap (52 articles): MISSING all 4 V14e articles.
The FR pages ARE live (both translated-slug and EN-slug return 200), but neither
the FR canonical slugs nor the EN slugs appear as <loc> entries in the FR sitemap.
Hreflang discrepancy: EN sitemap declares FR alternate as
/fr/blog/xnas-inversion-why-us-ceos-trick-insider-trading-models/ but the
actual FR canonical (from <link rel="canonical">) is
/fr/blog/xnas-inversion-pourquoi-les-ceo-americains-piegent-les-modeles-d-insider-trading/.
This is a real hreflang mismatch -- Google will see FR alternate pointing to the
EN-slug URL, not the canonical FR-slug URL.
FINDING I1 (HIGH): 4 V14e blog articles missing from FR sitemap. Plus hreflang in EN sitemap points to EN-slug URLs for FR locale instead of the translated FR canonical slugs. SEO impact: Googlebot may not index the FR versions of these articles correctly.
Section J -- Structured data (JSON-LD)
VERDICT: ALL_CLEAN
/fr/ JSON-LD: Organization + WebSite schemas. No strategy performance numbers present.
/fr/methodologie/ JSON-LD: TechArticle schema. No strategy numbers embedded.
No V14e figures (Sharpe, CAGR, MaxDD) appear in JSON-LD blocks, so no drift risk. The performance numbers live in the page body (React-rendered), not structured data.
Critical issues
| # | Severity | Section | Finding |
|---|---|---|---|
| I1 | HIGH | Sitemap / hreflang | 4 V14e FR blog articles absent from /sitemap-blog/fr/index.xml + hreflang in EN sitemap uses EN slug for FR locale instead of canonical FR slug |
| D2 | HIGH | Docs | ARCHITECTURE.md lines 98 + 320 document weekly-rescore as "Sun 04:00 UTC" -- actual schedule is daily |
| C1 | LOW | MCP | WinningSignal interface missing exitDate field (pubDate + holdingDays) |
| C2 | LOW | MCP | search_top_signals has no EU_strict market filter; returns global signals |
| D1 | LOW | Cron | weekly-rescore/route.ts file header comment says "Sun 04:00" but schedule is daily |
| H1 | LOW | Docs | ARCHITECTURE.md "Known debt" says no cron for signalScoreV13 backfill but daily weekly-rescore now handles it |
Action items (ordered by impact)
1. Fix FR blog sitemap -- HIGH (SEO) The 4 V14e articles are live at their FR canonical URLs but are invisible to Googlebot via the sitemap. Options: a. Trigger /api/cron/refresh-sitemap manually (if it reads from BlogArticle table). b. Check why the 4 articles are absent -- they may have a different status field or locale tag in the DB that excludes them from the sitemap generator.
2. Fix hreflang for V14e articles -- HIGH (SEO) The EN sitemap xhtml:link hreflang="fr" should point to the FR canonical slug (/fr/blog/xnas-inversion-pourquoi-...) not the EN slug. Check the sitemap generator to ensure it uses the locale-specific slug when building hreflang alternates.
3. Update ARCHITECTURE.md weekly-rescore schedule -- LOW (docs) Lines 98 and 320: replace "(Sun 04:00 UTC)" with "(daily 04:00 UTC, see vercel.json)". Also update the "Known debt" note at the signalScoreV13 paragraph to reflect that weekly-rescore now covers this via its third pass.
4. Fix route comment in weekly-rescore/route.ts -- LOW (docs) File header says "Schedule: 0 4 * * 0 (Sun 04:00 UTC)". Update to "0 4 * * * (daily)".
5. Add exitDate to WinningSignal -- LOW (UX)
Compute exitDate = new Date(pubDate.getTime() + WINNING_STRATEGY.holdingDays * 86400_000)
and expose it in the WinningSignal return. Useful for MCP consumers and /recommendations UI.
6. Optionally add EU_strict filter to search_top_signals -- LOW (consistency)
Not a bug (tool description doesn't promise EU filtering) but would align it with the
strategy's universe. Add an optional euStrict: boolean param or document the gap.