diff --git a/dashboard/backend/tests/test_admin_analytics_frontend.py b/dashboard/backend/tests/test_admin_analytics_frontend.py index fabcb83e..17431429 100644 --- a/dashboard/backend/tests/test_admin_analytics_frontend.py +++ b/dashboard/backend/tests/test_admin_analytics_frontend.py @@ -161,8 +161,8 @@ def test_profile_menu_admin_entry_opens_the_admin_page(): def test_app_lifecycle_and_cache_versions_are_wired(): # Lockstep owner for the console's bumped tags and the /admin page's pins: # every bump edits this test in the same change (Global Constraints). - assert 'styles.css?v=146' in APP_HTML - assert 'app.js?v=141' in APP_HTML + assert 'styles.css?v=147' in APP_HTML + assert 'app.js?v=142' in APP_HTML assert 'js/admin-tabs.js?v=12' in APP_HTML for tag in ( 'href="admin.css?v=4"', diff --git a/dashboard/backend/tests/test_analytics_frontend.py b/dashboard/backend/tests/test_analytics_frontend.py index b18d6c89..8f7eecd1 100644 --- a/dashboard/backend/tests/test_analytics_frontend.py +++ b/dashboard/backend/tests/test_analytics_frontend.py @@ -41,12 +41,12 @@ def _function_body(source: str, signature: str) -> str: def test_analytics_script_loads_between_app_and_page_scripts(): - app_at = APP_HTML.index('') + app_at = APP_HTML.index('') analytics_at = APP_HTML.index( '' ) editor_at = APP_HTML.index( - '' + '' ) assert app_at < analytics_at < editor_at diff --git a/dashboard/backend/tests/test_app_copy_register.py b/dashboard/backend/tests/test_app_copy_register.py index 8601177f..23480c54 100644 --- a/dashboard/backend/tests/test_app_copy_register.py +++ b/dashboard/backend/tests/test_app_copy_register.py @@ -97,9 +97,12 @@ def test_competition_organizer_line_is_present(): def test_capital_note_new_text_is_present(): + # Paper trading is switched off (PAPER_TRADING_ENABLED in app.js), so the + # Configure field is greyed and its note says so instead of describing a + # reservation nobody can make. assert ( - "Reserved from your My Portfolio balance while this agent paper-trades. " - "Backtests use a separate simulated amount and never touch it." + "Paper trading is not available yet. " + "Backtests use the simulated amount beside it." ) in _HTML diff --git a/dashboard/backend/tests/test_backtest_comparison_frontend.py b/dashboard/backend/tests/test_backtest_comparison_frontend.py index 0e363d17..664d8617 100644 --- a/dashboard/backend/tests/test_backtest_comparison_frontend.py +++ b/dashboard/backend/tests/test_backtest_comparison_frontend.py @@ -191,8 +191,8 @@ def test_exact_raw_ties_mark_every_tied_series_best(): def test_comparison_script_and_semantic_table_ship_before_app(): helper = '' - app = '' - assert 'href="styles.css?v=146"' in APP_HTML + app = '' + assert 'href="styles.css?v=147"' in APP_HTML assert APP_HTML.index(helper) < APP_HTML.index(app) for element_id in ( "performanceLegend", diff --git a/dashboard/backend/tests/test_frontend_fast_boot.py b/dashboard/backend/tests/test_frontend_fast_boot.py index 55aa99a5..09de5b54 100644 --- a/dashboard/backend/tests/test_frontend_fast_boot.py +++ b/dashboard/backend/tests/test_frontend_fast_boot.py @@ -191,9 +191,9 @@ def test_cache_busters_bumped(): # the next bump, so the exact one looks like the broken guard and gets # "fixed" by loosening it. That collision has already cost this repo one # round of follow-ups (#347/#348). - assert "app.js?v=141" in APP_HTML - assert "js/agent-editor.js?v=31" in APP_HTML - assert "styles.css?v=146" in APP_HTML + assert "app.js?v=142" in APP_HTML + assert "js/agent-editor.js?v=32" in APP_HTML + assert "styles.css?v=147" in APP_HTML assert "js/leaderboard.js?v=33" in APP_HTML assert "home-page.js?v=50" in APP_HTML assert "js/credit-format.js?v=1" in APP_HTML diff --git a/dashboard/backend/tests/test_my_agents_card_ui.py b/dashboard/backend/tests/test_my_agents_card_ui.py index ea81d612..25f1983a 100644 --- a/dashboard/backend/tests/test_my_agents_card_ui.py +++ b/dashboard/backend/tests/test_my_agents_card_ui.py @@ -1,11 +1,12 @@ -"""My Agents card: both capitals, and a signposted paper-trading affordance. +"""My Agents card: the capital figures, and paper trading switched off. The card showed only the paper sleeve directly above a **Run Backtest** button, which implied the figure was what the backtest would use -- it wasn't. Both -figures are now labelled side by side. +figures are now labelled side by side whenever paper trading is enabled. -Run Paper Trading ships disabled: execution/paper_backend.py is still a stub -(Phase B), and a greyed button with no explanation reads as a bug. +Paper trading is switched off product-wide (`PAPER_TRADING_ENABLED = false` +in app.js; execution/paper_backend.py is still a stub), so the shipped card +shows the backtest figure alone and offers no paper-trading button at all. """ import shutil @@ -49,9 +50,14 @@ def _run_node(script: str) -> str: return result.stdout -def _harness(body: str) -> str: - """Real functions lifted from app.js, with their few dependencies stubbed.""" +def _harness(body: str, paper_enabled: bool = True) -> str: + """Real functions lifted from app.js, with their few dependencies stubbed. + + ``paper_enabled`` defaults to True so the capital-resolution tests below + keep seeing both figures; the shipped value is pinned separately. + """ return f""" +const PAPER_TRADING_ENABLED = {"true" if paper_enabled else "false"}; const MAX_BACKTEST_ALLOCATED_CAPITAL = 3000; const DEFAULT_AGENT_CASH_ALLOCATION = 1000; function escapeHtml(s) {{ return String(s); }} @@ -62,6 +68,27 @@ def _harness(body: str) -> str: """ +def test_paper_trading_ships_switched_off(): + """The product decision itself: paper trading is disabled until it ships.""" + assert "const PAPER_TRADING_ENABLED = false;" in _APP_JS + + +def test_card_hides_the_paper_sleeve_when_paper_trading_is_off(): + out = _run_node( + _harness( + "console.log(renderAgentAllocatedCapitalHero(" + "{cash_allocation: 1000, backtest_allocation: 2500}));", + paper_enabled=False, + ) + ) + assert "Paper Trading" not in out + assert "From My Portfolio" not in out + assert "$1,000" not in out + assert "Backtesting" in out + assert "$2,500" in out + assert "agent-card-capitals--single" in out + + def test_card_shows_both_capitals(): out = _run_node( _harness( @@ -127,19 +154,25 @@ def test_a_saved_zero_backtest_capital_is_displayed_as_zero(): assert "$1,000" not in out -def test_run_paper_trading_button_is_disabled_and_explained(): +def test_cards_offer_no_paper_trading_button(): + """Paper trading is switched off: no greyed "Run Paper Trading" button.""" actions = _extract_function(_APP_JS, "renderAgentCardActions") - assert "Run Paper Trading" in actions - assert "disabled" in actions - assert "Paper trading is coming soon" in actions + assert ">Run Paper Trading<" not in actions -def test_run_paper_trading_is_absent_from_live_paper_cards(): - """Paper cards show Open Agent; a second paper button would be nonsense.""" - actions = _extract_function(_APP_JS, "renderAgentCardActions") - head, _, tail = actions.partition("if (statusKey === 'paper')") - branch, _, rest = tail.partition("} else {") - assert "Run Paper Trading" not in branch +def test_status_badge_never_says_paper_trading_while_it_is_off(): + """A live/paper deployment flag (or the guest demo's is_live mock) must not + resurrect the PAPER TRADING card while the feature is disabled.""" + fn = _extract_function(_APP_JS, "resolveAgentStatusBadge") + out = _run_node( + "const PAPER_TRADING_ENABLED = false;\n" + + fn + + "\nconsole.log(JSON.stringify([" + "resolveAgentStatusBadge({is_live: true}).key," + "resolveAgentStatusBadge({deployment_status: 'paper', run_count: 1}).key," + "]));" + ) + assert out.strip() == '["draft","backtested"]' def test_run_backtest_lands_on_my_agents(): diff --git a/dashboard/frontend/app.html b/dashboard/frontend/app.html index f62508de..10f75dd6 100644 --- a/dashboard/frontend/app.html +++ b/dashboard/frontend/app.html @@ -13,7 +13,7 @@ because every API call is a CORS request. --> - + @@ -31,7 +31,9 @@ account: { page: 'account' }, credits: { page: 'credits' }, backtest: { page: 'playground', playgroundTab: 'backtest' }, - paper: { page: 'playground', playgroundTab: 'paper' }, + // Paper trading is switched off (PAPER_TRADING_ENABLED in app.js): + // old ?view=paper links land on My Agents instead of a dead panel. + paper: { page: 'playground', playgroundTab: 'agents' }, agents: { page: 'playground', playgroundTab: 'agents' }, marketplace: { page: 'community' }, playground: { page: 'playground', playgroundTab: 'agents' }, @@ -61,6 +63,10 @@ if (saved && saved.page === 'playground' && saved.playgroundTab === 'marketplace') { return { page: 'community' }; } + // Paper trading is switched off; see the 'paper' entry above. + if (saved && saved.page === 'playground' && saved.playgroundTab === 'paper') { + return Object.assign({}, saved, { playgroundTab: 'agents' }); + } // The Daily Leaderboard became the Live Trading Leaderboard. // Anyone whose last visit was that tab has 'daily' in localStorage // (or 'season' from a build of this branch); left alone the key @@ -275,7 +281,7 @@
Optional — backtest and paper trading work without an account.
+Optional — backtests work without an account.