Skip to content

feat(ui): live trading leaderboard - #352

Merged
FlyM1ss merged 9 commits into
mainfrom
feat/season-leaderboard-ui
Aug 15, 2026
Merged

feat(ui): live trading leaderboard#352
FlyM1ss merged 9 commits into
mainfrom
feat/season-leaderboard-ui

Conversation

@FlyM1ss

@FlyM1ss FlyM1ss commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Renames the Daily Leaderboard tab to the Live Trading Leaderboard and opens it in Season 0.

UI only — there is no season engine yet. _normalize_period coerces an unknown period back to contest, so ?period=live returns HTTP 200 carrying the Competition board. The tab therefore renders in preview: real curves, full season chrome, and a banner stating that nothing on it is a standing. Detection compares the period requested against the period returned; when the engine ships and answers period: "live", the banner clears itself with no frontend change.

  • Supersedes chore(leaderboard): temporarily hide Daily Leaderboard #335. That PR hid the Daily subtab and paused the cron; this removes the tab and keeps the pause.
  • live is the canonical tab key. daily and season stay as aliases so deep links already in the wild resolve to the successor board instead of falling through to Competition.
  • "Live" names the direction the board runs, not brokered execution — the About card says simulated, no broker, no real capital, and a test pins it.
  • Landing Race.tsx copy corrected: it advertised a live board you could enter your agent in. Entries come from the curated dashboard/config/leaderboard.json roster, so no such path exists.

No backend source changes. Spec: docs/superpowers/specs/2026-08-15-live-trading-leaderboard-ui.md

Replaces the Daily Leaderboard tab with a two-week Live Season board.

The season engine is not built, so the tab renders in preview: real
curves from the Competition window, full season chrome, and a banner
saying no season has run. Preview is detected by comparing the period
requested against the period returned -- `_normalize_period` coerces an
unknown period back to `contest`, so a check against the response alone
cannot see it.

`?view=daily` / `#daily` and saved `competitionTab: 'daily'` alias to the
season tab; an unrecognised tab matches no panel and paints Competition
blank.

Payload contract and the decisions behind it:
docs/superpowers/specs/2026-08-15-live-season-leaderboard-ui.md

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9cV2UzLgdTVmwcHLAtJeA
@vercel

vercel Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agentic-trading-lab Ready Ready Preview Aug 15, 2026 5:31am

The Daily Leaderboard tab is gone, so the 22:30 UTC cron would keep
deploying every competition LLM nightly, billable, for a board with no
surface. Endpoint, secret and workflow_dispatch all stay -- the season
engine's nightly advance is this same call.

Adopts the pause from #335 so this PR supersedes it rather than
conflicting with it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9cV2UzLgdTVmwcHLAtJeA
@FlyM1ss

FlyM1ss commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator Author

Overlaps #335 — this PR supersedes it

@JinBoatus1's #335 (chore(leaderboard): temporarily hide Daily Leaderboard) reaches the same conclusion by a lighter route: hide the tab, redirect ?view=daily, pause the cron. This PR replaces the tab instead of parking it, so the two collide rather than compose:

Region #335 #352
app.html nav map daily: leaderboard season
migrateSavedNavState leaderboard season
subtab button hidden replaced by Live Season
About card hidden rewritten for seasons
app.js viewParamForNavState drops the daily branch returns season
app.js showCompetitionPanel redirect aliases daily/liveseason
test_frontend_daily_leaderboard.py +15 lines renamed away
cron schedule paused paused (adopted in c53e598)

Every region #335 touches, this PR also touches, and the test file is a rename/modify conflict. #335 is also cut from an older base (app.js?v=77→78; main ships 101).

Suggested ordering: close #335 in favour of this one — its cron pause is now carried here, and its "re-enable later" path is superseded by the season board actually shipping. That is Jinbo's call, not mine; if #335 should land first instead, say so and I will rebase this onto it.

FlyM1ss and others added 2 commits August 15, 2026 11:40
#335 hid the Daily Leaderboard subtab and paused its nightly cron. This
branch removes that tab outright and puts the season board in its place,
so every region #335 touched is rewritten here rather than combined:

- nav map / migrateSavedNavState: 'daily' now aliases to the season tab
  instead of falling through to Competition, so a deep link lands on the
  successor board rather than silently on a different one.
- showCompetitionPanel / navigateToPage / viewParamForNavState: same,
  plus the 'live' key.
- the subtab and the About card are deleted, not hidden.
- test_frontend_daily_leaderboard.py: deleted with the tab it pinned.
  Its one new case asserted the subtab carried `hidden`; the replacement
  file asserts the tab is absent from the UI entirely, which is strictly
  stronger. The other assertions were preserved through the rename.
- cache-buster floor keeps this branch's higher values (110/111), which
  clear main's merged 102/101.

The cron pause is kept as #335 wrote it, with the comment rewritten to
say why the schedule is off now: the board it fed no longer exists, and
the season engine's nightly advance is this same endpoint.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9cV2UzLgdTVmwcHLAtJeA
Settles the two naming questions the grilling session left open, and
fixes two honesty bugs the name change exposed.

Naming
- The board is the **Live Trading Leaderboard** (was the working title
  "Live Season"). The tab, the board title and the About card all use it.
- The tab key and API period become `live`. `season` and `daily` stay as
  aliases in NAV_VIEW_MAP, showCompetitionPanel, migrateSavedNavState and
  loadLeaderboardData, so ?view= deep links and saved localStorage from
  either earlier name land on the successor board. An unrecognised
  competitionTab matches no boot-CSS rule and no panel, so the failure
  mode being avoided is a blank Competition page, not a wrong tab.
- The current season is Season 0, the shakedown season; Season 1 is the
  first that counts.

Season 0 is falsy
`season?.number ? ... : 'Season —'` renders Season 0 as *no season at
all* — silently, and only for the season shipping right now. Both render
sites now go through displayedSeasonNumber(), which does an explicit
Number.isFinite check. Guarded by a source-shape test, because a test
that passes 3 cannot see this bug.

Two claims the UI was making and should not have been
- The subtitle fell back to `window.start_date` for its "last completed"
  date, so the board printed "last completed 2026-04-15" — a specific,
  plausible, entirely invented advance date sitting directly under the
  banner saying no season has run. That fallback is gone; only
  daily_status carries a real advance, and preview suppresses it outright.
- The season strip said "Next advance: nightly after the 16:00 ET close"
  unconditionally, promising a job that is not deployed. In preview it
  now reads "No advance scheduled".

"Live" is itself a claim, so the About card qualifies it: simulated
trading on real market data, no broker account, no real capital, no
order leaving the system. PR #328 puts brokered execution in non-goals
and execution/paper_backend.py is still a stub, so a board named for
live trading that never says "simulated" is the UI promising something
the system does not do. A guard test pins that disclaimer.

2866 passed, 78 skipped. Verified in a browser against a scratch-DB
backend: ?period=live really does come back as period=contest, the
preview banner fires, and none of the season chrome renders on the
Competition board (checked via getComputedStyle, not element.hidden —
a class-level `display` outranks the UA [hidden] rule and the attribute
lies about it).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9cV2UzLgdTVmwcHLAtJeA
@FlyM1ss FlyM1ss changed the title feat(ui): live season leaderboard feat(ui): live trading leaderboard Aug 15, 2026
@FlyM1ss

FlyM1ss commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator Author

#335 is merged, so the collision is resolved by merging main in (458a7d1) rather than by closing anything. Every region #335 touched — the nav map, showCompetitionPanel, navigateToPage, the subtab, the About card, the cron — is rewritten here, so the merge takes this side throughout. #335's one new test asserted the Daily subtab carried hidden; it is replaced by a test asserting the tab is absent from the UI entirely.

Board is now named per @FlyM1ss: Live Trading Leaderboard, opening in Season 0.

Race.tsx sold "Race on the live leaderboard / Paper trading on live
markets. Watch your agent climb against the community" over bullets
promising live prices and rankings that update as agents trade.

Every clause was false. Board entries come from the curated
config/leaderboard.json roster, so no user agent is on any board and no
entry path exists; Competition is a fixed historical window, so its
prices are not live and its rankings do not move; brokered execution is
a PR #328 non-goal with execution/paper_backend.py still a stub.

Now names the two boards the app actually serves, and discloses that the
Live Trading Leaderboard is in preview for Season 0 -- the landing-side
half of the board's own preview banner, since nothing renders that
banner one page upstream.

The claim survived because its guard was scoped one file too narrowly:
test_band_makes_no_paper_trading_claim bans paper[\s-]?trad in
WhyCare.tsx only, so it lived on in the neighbouring section. New guards
read the shipped bundle, not the TSX, so an unbuilt edit fails rather
than passing against stale text.

Bundle rebuilt per dashboard/landing/README.md; only the JS and CSS
hashes moved (the logo is byte-identical) and the hand-written auth
layer is unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9cV2UzLgdTVmwcHLAtJeA
@FlyM1ss
FlyM1ss marked this pull request as ready for review August 15, 2026 04:16
FlyM1ss and others added 2 commits August 15, 2026 13:05
Pair each board response with its own request (sequence guard + commit the
rendered board at the single render entry point), repaint the chrome on the
error path and before the fetch, and anchor every preview disclaimer on
evidence a season advanced rather than on the period string.

Also: drop the unreachable daily_status notice/poll machinery and its three
tests, remove the #335 daily->leaderboard redirect that undid the live alias,
hide Competition-only chrome on the live board, qualify the home blurb,
separate "API unreachable" from "no models ranked yet", take the user agent
off the Race illustration, widen the brokered-claim guard to every landing
component behind an explicit disclaimer allowlist, give the cache-buster
invariant one owner, and default the manual refresh to no model deploys.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Mutation testing found this guard green with the toggle deleted: it checked
that the element ids appeared in updateLeaderboardHeader, and a getElementById
whose result is discarded satisfies that exactly as well as a working toggle.
The pre-paint added for the cold-start window left the table behind: rerunning
the normal renderer over the cleared payload prints "No entries in this season
yet", which for the 30-60s of a free-tier cold start is a claim about the board
nobody can make, and leaving the old rows re-attributes them to the board being
opened. Static placeholder, no interpolation.
Both guards justified themselves with "brokered execution does not exist".
It does: execution/robinhood_live_service.py is the live-money path, mounted by
api/routers/robinhood_live.py, armed by ROBINHOOD_EXECUTE (default false). The
bans are still right — the Lab's Talk/Test/Race flow is simulated throughout and
paper_backend.py is a stub — but a guard that states a false reason gets "fixed"
by deleting the wrong thing. Hero's conditional sentence is accurate, and is now
allowlisted for that reason rather than exempted by scope.
@FlyM1ss
FlyM1ss merged commit 7db504d into main Aug 15, 2026
7 checks passed
@FlyM1ss
FlyM1ss deleted the feat/season-leaderboard-ui branch August 15, 2026 06:16
FlyM1ss added a commit that referenced this pull request Aug 15, 2026
Written 2026-08-09; PRs #352 and #357 shipped a different two-board
design six days later. Renames Replay/Forward Season to the shipped
Competition/Live Trading, moves the season cadence to two weeks
(SEASON_TRADING_DAYS = 10), and marks each Phase 1 task done,
superseded or still-valid with verified line numbers.

Two premise errors corrected at source:
- a custom instruction REPLACES SAFE_TRADING_PROMPT rather than
  competing with it, so Phase 0's stated reason to expect failure
  was wrong
- #homeGetStartedBtn was already wired on 2026-07-25 (08c85aa)

Records three consequences that are not cosmetic: the instruction
lock doubles to two weeks and is reopened, C8 now gates Season 1 of
an already-shipped board, and Task 7's guard would delete a guard
#357 added on purpose.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014K97GJdZ2yxAwQ3mhDaGBG
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant