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
4 changes: 2 additions & 2 deletions dashboard/backend/tests/test_admin_analytics_frontend.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"',
Expand Down
4 changes: 2 additions & 2 deletions dashboard/backend/tests/test_analytics_frontend.py
Original file line number Diff line number Diff line change
Expand Up @@ -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('<script src="app.js?v=141" defer></script>')
app_at = APP_HTML.index('<script src="app.js?v=142" defer></script>')
analytics_at = APP_HTML.index(
'<script src="js/analytics.js?v=1" defer></script>'
)
editor_at = APP_HTML.index(
'<script src="js/agent-editor.js?v=31" defer></script>'
'<script src="js/agent-editor.js?v=32" defer></script>'
)
assert app_at < analytics_at < editor_at

Expand Down
7 changes: 5 additions & 2 deletions dashboard/backend/tests/test_app_copy_register.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down
4 changes: 2 additions & 2 deletions dashboard/backend/tests/test_backtest_comparison_frontend.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = '<script src="js/backtest-comparison.js?v=1" defer></script>'
app = '<script src="app.js?v=141" defer></script>'
assert 'href="styles.css?v=146"' in APP_HTML
app = '<script src="app.js?v=142" defer></script>'
assert 'href="styles.css?v=147"' in APP_HTML
assert APP_HTML.index(helper) < APP_HTML.index(app)
for element_id in (
"performanceLegend",
Expand Down
6 changes: 3 additions & 3 deletions dashboard/backend/tests/test_frontend_fast_boot.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
65 changes: 49 additions & 16 deletions dashboard/backend/tests/test_my_agents_card_ui.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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); }}
Expand All @@ -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(
Expand Down Expand Up @@ -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():
Expand Down
57 changes: 36 additions & 21 deletions dashboard/frontend/app.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
because every API call is a CORS request. -->
<link rel="preconnect" href="https://agentictrading.onrender.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="styles.css?v=146">
<link rel="stylesheet" href="styles.css?v=147">
<!-- defer: ~200KB that was render-blocking. Deferred scripts execute in
document order (this one first, the body-end ones after), all before
DOMContentLoaded, so Chart is defined before any chart renders. -->
Expand All @@ -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' },
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -275,7 +281,7 @@ <h1>Agentic Trading Lab</h1>
<div class="auth-modal-panel" role="dialog" aria-labelledby="authModalTitle">
<button id="authModalClose" class="auth-modal-close" type="button" aria-label="Close">×</button>
<h2 id="authModalTitle" class="auth-modal-title">Sign in</h2>
<p id="authModalSubtitle" class="auth-modal-subtitle">Optional — backtest and paper trading work without an account.</p>
<p id="authModalSubtitle" class="auth-modal-subtitle">Optional — backtests work without an account.</p>
<form id="authForm" class="auth-form">
<label class="auth-field">
<span>Email</span>
Expand Down Expand Up @@ -317,7 +323,7 @@ <h2 id="authModalTitle" class="auth-modal-title">Sign in</h2>
<div class="auth-modal-panel run-backtest-modal-panel" role="dialog" aria-labelledby="runBacktestModalTitle">
<button id="runBacktestModalClose" class="auth-modal-close" type="button" aria-label="Close">×</button>
<h2 id="runBacktestModalTitle" class="auth-modal-title">Run Backtest</h2>
<p class="auth-modal-subtitle">Simulation settings for this agent. Does not change its Paper Trading Allocated Capital.</p>
<p class="auth-modal-subtitle">Simulation settings for this agent.</p>

<div class="run-backtest-modal-body">
<div class="control-group">
Expand Down Expand Up @@ -424,7 +430,7 @@ <h2 id="runBacktestModalTitle" class="auth-modal-title">Run Backtest</h2>
<p id="runBacktestCapitalValue" class="run-backtest-readonly">—</p>
<button id="runBacktestEditCapitalBtn" class="run-backtest-edit-link" type="button">Edit in Configure</button>
</div>
<p id="runBacktestCapitalHint" class="control-helper">Simulated starting cash. Does not change Paper Trading Allocated Capital.</p>
<p id="runBacktestCapitalHint" class="control-helper">Simulated starting cash.</p>
</div>

<div class="control-group" id="runBacktestBillingGroup">
Expand Down Expand Up @@ -842,12 +848,14 @@ <h2 id="createExternalAgentModalTitle" class="auth-modal-title">Register Externa
<span>Model name (optional)</span>
<input id="externalAgentModel" type="text" maxlength="100" placeholder="gpt-4 / rule-based" autocomplete="off">
</label>
<label class="auth-field">
<!-- Paper trading is switched off (PAPER_TRADING_ENABLED in app.js):
hidden and disabled, and the create posts cash_allocation 0. -->
<label class="auth-field" hidden>
<span>Paper Trading Allocated Capital (max $3,000)</span>
<input id="externalAgentCashAllocation" type="number" min="0" max="3000" step="any" data-cash-step="100" value="1000" required aria-describedby="externalAgentCashHint">
<input id="externalAgentCashAllocation" type="number" min="0" max="3000" step="any" data-cash-step="100" value="1000" required disabled aria-describedby="externalAgentCashHint">
<span class="capital-input-error" data-cash-error-slot role="alert" hidden></span>
</label>
<p id="externalAgentCashHint" class="credential-hint">Cash reserved from My Portfolio for this agent's paper trading. Backtests start from this amount by default but never spend it.</p>
<p id="externalAgentCashHint" class="credential-hint" hidden>Cash reserved from My Portfolio for this agent's paper trading. Backtests start from this amount by default but never spend it.</p>
<p id="createExternalAgentError" class="auth-error" hidden></p>
<button id="createExternalAgentSubmit" class="auth-submit-btn" type="submit">Create agent</button>
</form>
Expand Down Expand Up @@ -876,12 +884,14 @@ <h2 id="createBuiltinAgentModalTitle" class="auth-modal-title">Create a Built-in
<span>Description (optional)</span>
<input id="builtinAgentDescription" type="text" maxlength="280" placeholder="What makes this agent different?" autocomplete="off">
</label>
<label class="auth-field">
<!-- Paper trading is switched off (PAPER_TRADING_ENABLED in app.js):
hidden and disabled, and the create posts cash_allocation 0. -->
<label class="auth-field" hidden>
<span>Paper Trading Allocated Capital (max $3,000)</span>
<input id="builtinAgentCashAllocation" type="number" min="0" max="3000" step="any" data-cash-step="100" value="1000" required aria-describedby="builtinAgentCashHint">
<input id="builtinAgentCashAllocation" type="number" min="0" max="3000" step="any" data-cash-step="100" value="1000" required disabled aria-describedby="builtinAgentCashHint">
<span class="capital-input-error" data-cash-error-slot role="alert" hidden></span>
</label>
<p id="builtinAgentCashHint" class="credential-hint">Cash reserved from My Portfolio for this agent's paper trading. Backtests start from this amount by default but never spend it.</p>
<p id="builtinAgentCashHint" class="credential-hint" hidden>Cash reserved from My Portfolio for this agent's paper trading. Backtests start from this amount by default but never spend it.</p>
<p id="createBuiltinAgentError" class="auth-error" hidden></p>
<button id="createBuiltinAgentSubmit" class="auth-submit-btn" type="submit">Create built-in agent</button>
</form>
Expand Down Expand Up @@ -932,19 +942,21 @@ <h2 id="agentCredentialsModalTitle" class="auth-modal-title">Agent created</h2>
<div class="subtab-bar playground-subtabs">
<button class="subtab-btn active" data-playground-tab="agents">My Agents</button>
<button class="subtab-btn" data-playground-tab="backtest">Backtest</button>
<button class="subtab-btn" data-playground-tab="paper">Paper Trading</button>
<button class="subtab-btn subtab-btn--disabled" data-playground-tab="paper" disabled aria-disabled="true" title="Paper trading is coming soon">Paper Trading</button>
</div>
<div id="playgroundAgentsPanel" class="playground-panel">
<!-- My Portfolio: Overview + Capital Allocation (live ledger when signed in, sample data for guests) -->
<div class="page-header">
<!-- My Portfolio: Overview + Capital Allocation (live ledger when signed in, sample data for guests).
Hidden while paper trading is switched off (PAPER_TRADING_ENABLED in app.js): the
ledger only funds paper sleeves. portfolio.js still renders into it unchanged. -->
<div class="page-header" data-paper-trading-only hidden>
<div>
<h2 class="page-title">My Portfolio
<span id="portfolioSampleBadge" title="Illustrative sample data — not a real brokerage account." style="display:inline-block; vertical-align:middle; margin-left:8px; padding:2px 9px; border-radius:999px; font-size:11px; font-weight:700; letter-spacing:.04em; background:rgba(245,158,11,.15); color:#f59e0b; border:1px solid rgba(245,158,11,.4);">SAMPLE DATA</span>
</h2>
</div>
</div>

<div class="portfolio-top-grid">
<div class="portfolio-top-grid" data-paper-trading-only hidden>
<section class="section-card pf-overview-card" id="portfolioOverviewCard" aria-label="Portfolio Overview">
<!-- filled by portfolio.js -->
</section>
Expand Down Expand Up @@ -1157,11 +1169,14 @@ <h3 class="agent-editor-intro-title">Robinhood live trading</h3>
<div class="agent-capital-card section-card compact">
<h3 class="agent-capital-title">Allocated Capital</h3>
<div class="agent-capital-grid">
<label class="agent-capital-field" for="agentEditorCashAllocation">
<span class="agent-capital-label">Paper Trading <span class="agent-capital-max">max $3,000</span></span>
<input id="agentEditorCashAllocation" class="agent-capital-input" type="number" min="0" max="3000" step="any" data-cash-step="100" placeholder="1000" aria-label="Paper Trading Allocated Capital">
<!-- Greyed while paper trading is switched off (PAPER_TRADING_ENABLED
in app.js). agent-editor.js reads `disabled` as "leave the saved
sleeve alone" and omits cash_allocation from the PATCH. -->
<label class="agent-capital-field agent-capital-field--disabled" for="agentEditorCashAllocation" title="Paper trading is coming soon">
<span class="agent-capital-label">Paper Trading <span class="agent-capital-max">coming soon</span></span>
<input id="agentEditorCashAllocation" class="agent-capital-input" type="number" min="0" max="3000" step="any" data-cash-step="100" placeholder="1000" aria-label="Paper Trading Allocated Capital" disabled aria-disabled="true">
<span class="capital-input-error" data-cash-error-slot role="alert" hidden></span>
<span class="agent-capital-note">Reserved from your My Portfolio balance while this agent paper-trades. Backtests use a separate simulated amount and never touch it.</span>
<span class="agent-capital-note">Paper trading is not available yet. Backtests use the simulated amount beside it.</span>
</label>
<label class="agent-capital-field" for="agentEditorBacktestAllocation">
<span class="agent-capital-label">Backtesting <span class="agent-capital-max">max $3,000</span></span>
Expand Down Expand Up @@ -2393,9 +2408,9 @@ <h2 id="creditsRefundTitle">Refund Credits purchase</h2>
<script src="market-events/MarketEventFeed.js" defer></script>
<script src="js/portfolio.js?v=18" defer></script>
<script src="js/backtest-comparison.js?v=1" defer></script>
<script src="app.js?v=141" defer></script>
<script src="app.js?v=142" defer></script>
<script src="js/analytics.js?v=1" defer></script>
<script src="js/agent-editor.js?v=31" defer></script>
<script src="js/agent-editor.js?v=32" defer></script>
<script src="js/credit-format.js?v=1" defer></script>
<script src="js/credits.js?v=8" defer></script>
<script src="js/admin-credits.js?v=8" defer></script>
Expand Down
Loading
Loading