Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions .github/workflows/daily-leaderboard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,17 @@ name: Daily Leaderboard refresh
#
# Requires repository secret LEADERBOARD_DAILY_REFRESH_SECRET matching
# the value configured on the Render service.
#
# UI is temporarily hidden (Daily Leaderboard subtab parked). The nightly
# schedule is paused until model curves deploy reliably — keep
# workflow_dispatch so operators can still trigger a refresh by hand.
# To re-enable: restore the `schedule:` block below and un-hide the subtab
# in dashboard/frontend/app.html (+ the navigateToPage redirect in app.js).

on:
schedule:
# 22:30 UTC Mon–Fri ≈ 18:30 EDT / 17:30 EST — after the 16:00 ET cash close.
- cron: "30 22 * * 1-5"
# schedule:
# # 22:30 UTC Mon–Fri ≈ 18:30 EDT / 17:30 EST — after the 16:00 ET cash close.
# - cron: "30 22 * * 1-5"
workflow_dispatch:
inputs:
deploy_models:
Expand Down
15 changes: 15 additions & 0 deletions dashboard/backend/tests/test_frontend_daily_leaderboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,18 @@ def test_leaderboard_cache_buster_bumped():
match = re.search(r"js/leaderboard\.js\?v=(\d+)", _APP_HTML)
assert match, "leaderboard.js must be loaded with a ?v= cache buster"
assert int(match.group(1)) >= 19


def test_daily_leaderboard_subtab_is_parked():
"""UI is hidden until daily model deploys are reliable; backend stays.

Re-enable by removing ``hidden`` from the subtab (and About card), restoring
``NAV_VIEW_MAP['daily']`` → ``competitionTab: 'daily'``, dropping the
navigateToPage redirect in app.js, and turning the workflow schedule back on.
"""
assert re.search(
r'data-competition-tab="daily"[^>]*\bhidden\b',
_APP_HTML,
), "Daily Leaderboard subtab must stay hidden while the board is parked"
assert "competitionTab: 'leaderboard'" in _APP_HTML
assert re.search(r"\bdaily\s*:\s*\{[^}]*competitionTab:\s*'leaderboard'", _APP_HTML)
2 changes: 1 addition & 1 deletion dashboard/backend/tests/test_frontend_fast_boot.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,5 +183,5 @@ def test_cache_busters_bumped():
# branch started from. Two branches cut from different bases can both
# "bump" to the same number, merge without a conflict, and leave prod
# serving new app.js content under a ?v= browsers have already cached.
assert "app.js?v=101" in APP_HTML
assert "app.js?v=102" in APP_HTML
assert "styles.css?v=101" in APP_HTML
16 changes: 12 additions & 4 deletions dashboard/frontend/app.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@
playground: { page: 'playground', playgroundTab: 'agents' },
'my-algo': { page: 'playground', playgroundTab: 'agents' },
contest: { page: 'competition', competitionTab: 'leaderboard' },
daily: { page: 'competition', competitionTab: 'daily' },
// Daily Leaderboard UI is temporarily retired (backend/cron kept).
// ?view=daily deep links fall through to the contest board.
daily: { page: 'competition', competitionTab: 'leaderboard' },
competition: { page: 'competition', competitionTab: 'leaderboard' },
leaderboard: { page: 'competition', competitionTab: 'leaderboard' },
participants: { page: 'competition', competitionTab: 'participants' },
Expand All @@ -52,6 +54,10 @@
if (saved && saved.page === 'playground' && saved.playgroundTab === 'marketplace') {
return { page: 'community' };
}
// Daily Leaderboard tab is hidden until the deploy pipeline is fixed.
if (saved && saved.page === 'competition' && saved.competitionTab === 'daily') {
return { page: 'competition', competitionTab: 'leaderboard' };
}
return saved;
}
window.migrateSavedNavState = migrateSavedNavState;
Expand Down Expand Up @@ -1455,7 +1461,8 @@ <h3>Stop Loss / Take Profit</h3>
<div id="competitionView" class="page-view competition-view" style="display: none;">
<div class="subtab-bar competition-subtabs">
<button class="subtab-btn active" data-competition-tab="leaderboard">Competition Leaderboard</button>
<button class="subtab-btn" data-competition-tab="daily">Daily Leaderboard</button>
<!-- hidden: Daily Leaderboard UI parked until model curves deploy reliably. Backend + workflow_dispatch kept. -->
<button class="subtab-btn" data-competition-tab="daily" hidden>Daily Leaderboard</button>
<button class="subtab-btn" data-competition-tab="participants">Participating Teams</button>
<button class="subtab-btn" data-competition-tab="about">About</button>
</div>
Expand All @@ -1474,7 +1481,8 @@ <h3>Stop Loss / Take Profit</h3>
<h3 class="section-title">Competition Overview</h3>
<p class="about-text">SecureFinAI Contest 2026 is a paper-trading competition for AI-powered agents. The contest is currently in <strong>Preseason</strong>. Participating teams join when the season starts (registration Aug 2026).</p>
</div>
<div class="section-card">
<!-- hidden with the Daily Leaderboard subtab; restore when that tab ships again. -->
<div class="section-card" hidden>
<h3 class="section-title">Daily Leaderboard</h3>
<p class="about-text">The Daily Leaderboard is the same chart + standings UI as Competition, but each entry is an hourly backtest over the <strong>last completed US cash session</strong> (after 16:00 ET that weekday; before the close, the prior session). Baseline and index lines refresh automatically on load. New AI entries appear when the leaderboard next updates.</p>
</div>
Expand Down Expand Up @@ -1840,7 +1848,7 @@ <h2 class="page-title">Admin</h2>
<script src="market-events/MarketEventFeed.js" defer></script>
<script src="js/portfolio.js?v=17" defer></script>
<script src="js/agent-editor.js?v=27" defer></script>
<script src="app.js?v=101" defer></script>
<script src="app.js?v=102" defer></script>
<script src="js/leaderboard.js?v=19" defer></script>
<script src="home-page.js?v=37" defer></script>
<!-- Load order: must come after app.js (API/API_BASE/escapeHtml) and
Expand Down
16 changes: 15 additions & 1 deletion dashboard/frontend/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -7643,7 +7643,7 @@ function viewParamForNavState(state) {
return 'agents';
}
if (state.page === 'competition') {
if (state.competitionTab === 'daily') return 'daily';
// Daily tab is hidden; never emit ?view=daily while it is parked.
if (state.competitionTab === 'participants') return 'participants';
if (state.competitionTab === 'about') return 'about';
return 'leaderboard';
Expand Down Expand Up @@ -7944,6 +7944,13 @@ function showPlaygroundPanel(tab) {
}

function showCompetitionPanel(tab) {
// Belt and braces with navigateToPage's redirect: a stray click on the
// hidden Daily button (or a caller that bypasses navigateToPage) must not
// paint the unfinished board.
if (tab === 'daily') {
tab = 'leaderboard';
}

competitionTab = tab;
updateCompetitionSubtabs();

Expand Down Expand Up @@ -7984,6 +7991,13 @@ function navigateToPage(page, options = {}) {
page = 'community';
options = { ...options, playgroundTab: 'agents' };
}
// Daily Leaderboard UI is parked (models not deploying reliably). Keep the
// backend + leaderboard.js path, but never land on the hidden subtab —
// including ?view=daily bookmarks and a session that still has competitionTab
// saved as 'daily'.
if (page === 'competition' && (options.competitionTab || competitionTab) === 'daily') {
options = { ...options, competitionTab: 'leaderboard' };
}
// Role-gate the admin shell in the UI too, not only its APIs: without
// this, anyone landing on ?view=admin saw the empty console chrome until
// the deferred boot /me settled — tens of seconds on a cold free-tier
Expand Down
Loading