/* global React */ const { useState, useEffect, useRef, useCallback } = React; // Shared number formatter: "not reported" is a dash, never 0. const fmt = (v, digits = 2) => v === null || v === undefined || Number.isNaN(v) ? '-' : Number(v).toLocaleString(undefined, { maximumFractionDigits: digits }); // ============================================================ // HOME PAGE // ============================================================ const Home = ({ onNav }) => { const D = window.RLX_DATA; const research = D.researchRows || []; const optrl = D.optrlRows || []; const playground = D.playgroundRows || []; // Distinct values of a CSV column across every board. const uniqueCount = (field) => new Set( [...research, ...optrl, ...playground].map(r => r[field]).filter(Boolean) ).size; const byMean = (rows) => [...rows] .filter(r => r.mean_reward != null) .sort((a, b) => b.mean_reward - a.mean_reward) .slice(0, 3); const topPub = byMean(research); const topOpt = byMean(optrl); return (

The public RL benchmark. // maintained by OptRL Lab

Rank the latest published algorithms against OptRL's proprietary baselines, on environments that touch real-world operations, warehouses, inventory, portfolios, freight. Try them yourself in the playground.
{/* Every tile below is counted from live board data. Nothing is hardcoded: a tile with no data reads 0, not a stale number. */}
Benchmark entries
{research.length + optrl.length + playground.length}
{research.length} research · {optrl.length} optrl · {playground.length} playground
Algorithms
{uniqueCount('algorithm')}
{uniqueCount('learning_type')} learning types
Environments
{uniqueCount('environment')}
across {uniqueCount('benchmark_suite')} benchmark suites
Community runs
{playground.length}
published from the OptRL Playground

01 /Top 3, Research

{topPub.length === 0 && (
No research benchmarks loaded yet.
)} {topPub.map((r, i) => (
{i+1}
{r.benchmark_suite}
{r.algorithm}
{r.environment} · {r.learning_type || '-'}
mean {fmt(r.mean_reward)} sd {fmt(r.std_reward)}
))}

02 /Top 3, OptRL

{topOpt.length === 0 && (
No OptRL benchmarks loaded yet.
)} {topOpt.map((r, i) => (
{i+1}
{r.benchmark_suite}
{r.algorithm}
{r.environment} · {r.learning_type || '-'}
mean {fmt(r.mean_reward)} {r.success_rate != null ? r.success_rate.toFixed(1) + '%' : '-'}
))}

03 /Try it in OptRL Playground

OptRL Playground is a separate interactive product, pick an algo, run it on a real operational env, publish your run back here.
{D.playgroundEnvs.map(e => (
{ window.location.href = '/dashboard/?env=' + encodeURIComponent(e.id); }} style={{cursor: 'pointer'}}>
{e.name}
{e.description.slice(0, 60)}…
obs={e.obsDim} act={e.actDim}
))}
); }; // ============================================================ // ADMIN // ============================================================ // Sign-in gate. The admin API is cookie+bearer authenticated; until // we hold a token there is nothing useful to render here. const AdminLogin = ({ onDone }) => { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [busy, setBusy] = useState(false); const [err, setErr] = useState(null); const submit = async (e) => { e.preventDefault(); setBusy(true); setErr(null); try { await window.RLX_API.login(email.trim(), password); onDone(); } catch (ex) { setErr(ex.message || 'login failed'); } finally { setBusy(false); } }; return (

RLX Admin// sign in

Upload Research and OptRL benchmark sheets, review submissions, manage users, and audit actions.
admin credentials
setEmail(e.target.value)} placeholder="admin@optrl.lab" data-testid="admin-email" style={{width: '100%', padding: 8, marginBottom: 8, fontFamily: 'var(--mono)', fontSize: 13}} /> setPassword(e.target.value)} placeholder="password" data-testid="admin-password" style={{width: '100%', padding: 8, marginBottom: 12, fontFamily: 'var(--mono)', fontSize: 13}} /> {err && (
{err}
)}
); }; const Admin = () => { const [authed, setAuthed] = useState(() => window.RLX_API.isAuthed()); const [section, setSection] = useState('upload'); const [profile, setProfile] = useState(null); const [reloadingCache, setReloadingCache] = useState(false); const [cacheMsg, setCacheMsg] = useState(null); const fetchProfile = useCallback(() => { if (!window.RLX_API.isAuthed()) return; window.RLX_API.whoami() .then(p => setProfile(p)) .catch(() => {}); }, []); useEffect(() => { if (authed) { fetchProfile(); } }, [authed, fetchProfile]); useEffect(() => { const handleAuth = (e) => setAuthed(e.detail.authed); window.addEventListener('rlx:auth', handleAuth); return () => window.removeEventListener('rlx:auth', handleAuth); }, []); if (!authed) return setAuthed(true)} />; const nav = [ { id: 'upload', label: 'Upload Sheet' }, { id: 'analytics', label: 'Analytics' }, { id: 'users', label: 'User Management' }, { id: 'audit', label: 'Audit Log' }, { id: 'admins', label: 'Staff Admins' }, ]; const signOut = () => { window.RLX_API.logout(); setAuthed(false); }; const handleReloadCache = async () => { setReloadingCache(true); setCacheMsg(null); try { await window.RLX_API.reloadCache(); setCacheMsg('Cache reloaded!'); setTimeout(() => setCacheMsg(null), 4000); } catch (e) { setCacheMsg('Failed: ' + (e.message || 'error')); setTimeout(() => setCacheMsg(null), 4000); } finally { setReloadingCache(false); } }; return (

RLX Admin // internal · optrl.lab

Upload Research and OptRL benchmark sheets, monitor platform analytics, manage users, and audit actions.
{profile && (
Operator: {profile.email} {profile.role}
)}
signed in { e.preventDefault(); signOut(); }} style={{color: 'var(--ink-3)'}} data-testid="admin-signout">sign out
{nav.map(n => ( ))}
{cacheMsg &&
{cacheMsg}
}
{section === 'upload' && } {section === 'analytics' && } {section === 'users' && } {section === 'audit' && } {section === 'admins' && }
); }; // Real CSV ingestion. const AdminUpload = () => { const [drag, setDrag] = useState(false); const [source, setSource] = useState('paper'); const [mode, setMode] = useState('upsert'); const [busy, setBusy] = useState(false); const [result, setResult] = useState(null); const [err, setErr] = useState(null); const [history, setHistory] = useState([]); const inputRef = useRef(null); const loadHistory = () => { window.RLX_API.uploadHistory(10) .then(b => setHistory(b.entries || [])) .catch(() => {}); }; useEffect(() => { loadHistory(); }, []); const send = async (f) => { if (!f) return; setBusy(true); setErr(null); setResult(null); try { const body = await window.RLX_API.upload(f, source, mode); setResult(body); await window.RLX_API.refresh(); loadHistory(); } catch (ex) { setErr(ex.message || 'upload failed'); } finally { setBusy(false); } }; return (

UP /Upload Benchmark Sheet

Board
On duplicate
playground rows are published by users, not uploaded
send(e.target.files[0])} />
{ e.preventDefault(); setDrag(true); }} onDragOver={e => { e.preventDefault(); setDrag(true); }} onDragLeave={() => setDrag(false)} onDrop={e => { e.preventDefault(); setDrag(false); send(e.dataTransfer.files[0]); }} onClick={() => inputRef.current && inputRef.current.click()} >
{busy ? 'uploading…' : 'Drop .csv here'}
Algorithm, Environment, Learning Type, Benchmark Suite, Mean Reward, Stability (SD/SE), Success Rate (%), Training Steps, Min Reward, Max Reward, Primary Citation
only Algorithm and Environment are required
{err && (
upload failed · {err}
)} {result && (
{result.filename} · {result.source} · mode {result.mode} {result.status}
{[ ['inserted', result.rows_inserted, 'var(--ok)'], ['updated', result.rows_updated, 'var(--accent)'], ['unchanged', result.rows_unchanged, 'var(--ink-3)'], ['failed', result.rows_failed, result.rows_failed ? 'var(--bad)' : 'var(--ink-3)'], ].map(([k, v, c]) => (
{k}
{v}
))}
live on the public leaderboard now: other clients pick it up within 5s
{result.errors && result.errors.length > 0 && (
row errors (first 10)
{result.errors.slice(0, 10).map((e, i) => ( ))}
RowErrorDetail
{e.row} {e.error} {e.detail}
)}
)}
recent uploads
{history.length === 0 && ( )} {history.map(u => ( ))}
FileBoardInsUpd UnchFailUploadedStatus
no uploads yet
{u.filename} {u.source} {u.rows_inserted} {u.rows_updated} {u.rows_unchanged} {u.rows_failed} {(u.created_at || '').replace('T', ' ').slice(0, 16)} {u.status}
); }; const AdminAnalytics = () => { const [windowDays, setWindowDays] = useState(30); const [summary, setSummary] = useState(null); const [submissions, setSubmissions] = useState(null); const [loading, setLoading] = useState(true); const [err, setErr] = useState(null); const loadData = useCallback(() => { setLoading(true); setErr(null); Promise.all([ window.RLX_API.analyticsSummary(windowDays), window.RLX_API.analyticsSubmissions(windowDays), ]) .then(([sum, sub]) => { setSummary(sum); setSubmissions(sub); }) .catch(e => setErr(e.message || 'Failed to load analytics')) .finally(() => setLoading(false)); }, [windowDays]); useEffect(() => { loadData(); }, [loadData]); const calcDiff = (curr, prior) => { if (prior === 0) return curr > 0 ? `+${curr}` : '0'; const diff = curr - prior; return diff >= 0 ? `+${diff} vs prev` : `${diff} vs prev`; }; const calcPct = (curr, prior) => { if (prior === 0) return curr > 0 ? '↑ 100%' : '-'; const pct = ((curr - prior) / prior) * 100; return `${pct >= 0 ? '↑' : '↓'} ${Math.abs(pct).toFixed(0)}% vs prev`; }; const buckets = submissions?.buckets || []; const maxCount = Math.max(...buckets.map(b => b.count), 5); return (

A /Analytics

{[7, 30, 90].map(d => ( ))}
{err &&
{err}
} {summary && (
Total runs · {windowDays}d
{summary.total_runs_window}
= summary.total_runs_prior ? 'var(--ok)' : 'var(--bad)'}}> {calcPct(summary.total_runs_window, summary.total_runs_prior)}
Verified rate
{(summary.verified_rate * 100).toFixed(0)}%
{summary.verified_count} verified of {summary.total_runs_window}
Top env
{summary.top_env ? summary.top_env.env_key : '-'}
{summary.top_env ? `${summary.top_env.count} runs (${(summary.top_env.share * 100).toFixed(0)}%)` : 'No runs'}
New users · {windowDays}d
{summary.new_users_window}
{calcDiff(summary.new_users_window, summary.new_users_prior)}
Best S2R Gap ★
{summary.best_s2r_gap ? summary.best_s2r_gap.s2r_gap.toFixed(3) : '-'}
{summary.best_s2r_gap ? summary.best_s2r_gap.algorithm : 'No data yet'}
)} {/* Real Histogram Chart */}
daily submission volume · last {windowDays}d (real live data)
{submissions?.total || 0} total submissions
{buckets.length === 0 ? (
No submission data in this window
) : (
{buckets.map((b, i) => { const totalW = Math.max(buckets.length * 24, 600); const step = totalW / buckets.length; const barW = Math.max(step - 4, 6); const h = (b.count / maxCount) * 140; const x = i * step + 2; const y = 160 - h; return ( {`${b.date}: ${b.count} runs`} 0 ? 3 : 0)} fill={b.count > 0 ? (i >= buckets.length - 3 ? 'var(--accent)' : 'var(--ink)') : 'var(--rule)'} opacity={b.count > 0 ? (i >= buckets.length - 3 ? 0.9 : 0.6) : 0.2} /> ); })}
{buckets[0]?.date} {buckets[Math.floor(buckets.length / 2)]?.date} {buckets[buckets.length - 1]?.date}
)}
); }; const AdminUsers = () => { const [users, setUsers] = useState([]); const [total, setTotal] = useState(0); const [role, setRole] = useState(''); const [verified, setVerified] = useState(''); const [suspended, setSuspended] = useState(''); const [loading, setLoading] = useState(true); const [err, setErr] = useState(null); // Invite modal const [inviteOpen, setInviteOpen] = useState(false); const [inviteForm, setInviteForm] = useState({ display_name: '', social_platform: 'x', social_handle: '', role: 'contributor' }); const [inviting, setInviting] = useState(false); // Role & Suspend modals const [roleModal, setRoleModal] = useState(null); const [suspendModal, setSuspendModal] = useState(null); const [actionBusy, setActionBusy] = useState(false); const loadUsers = useCallback(() => { setLoading(true); setErr(null); const params = { limit: 50 }; if (role) params.role = role; if (verified !== '') params.verified = verified; if (suspended !== '') params.is_suspended = suspended; window.RLX_API.listUsers(params) .then(res => { setUsers(res.entries || []); setTotal(res.total || 0); }) .catch(e => setErr(e.message || 'Failed to load users')) .finally(() => setLoading(false)); }, [role, verified, suspended]); useEffect(() => { loadUsers(); }, [loadUsers]); const submitInvite = async (e) => { e.preventDefault(); setInviting(true); try { await window.RLX_API.inviteUser({ display_name: inviteForm.display_name.trim() || null, social_platform: inviteForm.social_platform.trim() || null, social_handle: inviteForm.social_handle.trim().replace(/^@/, '') || null, role: inviteForm.role, }); setInviteOpen(false); setInviteForm({ display_name: '', social_platform: 'x', social_handle: '', role: 'contributor' }); loadUsers(); } catch (ex) { alert('Invite failed: ' + (ex.message || 'error')); } finally { setInviting(false); } }; const submitRoleChange = async () => { if (!roleModal) return; setActionBusy(true); try { await window.RLX_API.changeUserRole(roleModal.user.id, roleModal.role); setRoleModal(null); loadUsers(); } catch (ex) { alert('Role update failed: ' + (ex.message || 'error')); } finally { setActionBusy(false); } }; const submitSuspend = async () => { if (!suspendModal) return; setActionBusy(true); try { await window.RLX_API.suspendUser(suspendModal.user.id, suspendModal.is_suspended, suspendModal.reason.trim() || null); setSuspendModal(null); loadUsers(); } catch (ex) { alert('Suspension update failed: ' + (ex.message || 'error')); } finally { setActionBusy(false); } }; return (

U /User Management

Role Verified Status
{err &&
{err}
}
{loading && } {!loading && users.length === 0 && ( )} {!loading && users.map(u => ( ))}
User ID Handle / Name Role Runs Joined Verified Status Actions
Loading users…
No users found
{u.id.slice(0, 8)}… {u.social_handle ? `@${u.social_handle}` : u.display_name || '@anonymous'} {u.display_name && u.social_handle && ( ({u.display_name}) )} {u.role} {u.session_count || 0} {(u.created_at || '').slice(0, 10)} {u.social_handle ? yes : no} {u.is_suspended ? suspended : active}
{u.is_suspended ? ( ) : ( )}
{/* Invite Modal */} {inviteOpen && (
!inviting && setInviteOpen(false)}>
e.stopPropagation()} style={{maxWidth: 440}}>
Invite / Pre-register User
Display Name
setInviteForm({...inviteForm, display_name: e.target.value})} placeholder="e.g. Alice Chen" style={{width: '100%', padding: 8, fontFamily: 'var(--mono)', fontSize: 12, marginBottom: 10}} />
Social Handle
setInviteForm({...inviteForm, social_handle: e.target.value})} placeholder="e.g. alice_rl" style={{width: '100%', padding: 8, fontFamily: 'var(--mono)', fontSize: 12, marginBottom: 10}} />
Social Platform
setInviteForm({...inviteForm, social_platform: e.target.value})} placeholder="x" style={{width: '100%', padding: 8, fontFamily: 'var(--mono)', fontSize: 12, marginBottom: 10}} />
Role
)} {/* Role Change Modal */} {roleModal && (
!actionBusy && setRoleModal(null)}>
e.stopPropagation()} style={{maxWidth: 380}}>
Change Role · {roleModal.user.social_handle || roleModal.user.display_name || roleModal.user.id.slice(0, 8)}
Select New Role:
)} {/* Suspend / Unsuspend Modal */} {suspendModal && (
!actionBusy && setSuspendModal(null)}>
e.stopPropagation()} style={{maxWidth: 420}}>
{suspendModal.is_suspended ? 'Suspend User' : 'Unsuspend User'}
{suspendModal.is_suspended ? `Are you sure you want to suspend this user? They will be blocked from launching new training sessions.` : `Are you sure you want to unsuspend this user? Their session creation capability will be restored.`}
{suspendModal.is_suspended && (
Suspension Reason:
setSuspendModal({...suspendModal, reason: e.target.value})} placeholder="e.g. Bot traffic, rate limit violation" style={{width: '100%', padding: 8, fontFamily: 'var(--mono)', fontSize: 12, marginBottom: 14}} />
)}
)}
); }; const AdminAudit = () => { const [entries, setEntries] = useState([]); const [total, setTotal] = useState(0); const [targetTable, setTargetTable] = useState(''); const [action, setAction] = useState(''); const [offset, setOffset] = useState(0); const limit = 50; const [loading, setLoading] = useState(true); const [err, setErr] = useState(null); const [inspectEntry, setInspectEntry] = useState(null); const loadAudit = useCallback(() => { setLoading(true); setErr(null); const params = { limit, offset }; if (targetTable) params.target_table = targetTable; if (action.trim()) params.action = action.trim(); window.RLX_API.listAuditLog(params) .then(res => { setEntries(res.entries || []); setTotal(res.total || 0); }) .catch(e => setErr(e.message || 'Failed to load audit log')) .finally(() => setLoading(false)); }, [targetTable, action, offset]); useEffect(() => { loadAudit(); }, [loadAudit]); return (

L /Audit Log

{total} total audit records
Table Action { setAction(e.target.value); setOffset(0); }} className="chip" style={{padding: '4px 8px', width: 160}} />
{err &&
{err}
}
{loading && } {!loading && entries.length === 0 && ( )} {!loading && entries.map(l => ( ))}
Timestamp Actor Action Target Reason Diff
Loading audit records…
No audit records found
{(l.created_at || '').replace('T', ' ').slice(0, 19)} {l.actor_type}: {l.actor_id} {l.action} {l.target_table} ({l.target_id ? (l.target_id.length > 10 ? l.target_id.slice(0, 8) + '…' : l.target_id) : '-'}) {l.reason || '-'} {(l.before_state || l.after_state) ? ( ) : ( none )}
{total > limit && (
Showing {offset + 1}–{Math.min(offset + limit, total)} of {total}
)} {/* Inspect Diff Modal */} {inspectEntry && (
setInspectEntry(null)}>
e.stopPropagation()} style={{maxWidth: 680}}>
Audit State Mutation · {inspectEntry.action}
BEFORE STATE
{JSON.stringify(inspectEntry.before_state || {}, null, 2)}
AFTER STATE
{JSON.stringify(inspectEntry.after_state || {}, null, 2)}
Target: {inspectEntry.target_table} · ID: {inspectEntry.target_id} · At: {inspectEntry.created_at}
)}
); }; const AdminAdmins = ({ currentAdminId }) => { const [admins, setAdmins] = useState([]); const [loading, setLoading] = useState(true); const [err, setErr] = useState(null); const [createOpen, setCreateOpen] = useState(false); const [createForm, setCreateForm] = useState({ email: '', password: '', role: 'admin' }); const [creating, setCreating] = useState(false); const [pwdModal, setPwdModal] = useState(null); const [actionBusy, setActionBusy] = useState(false); const loadAdmins = useCallback(() => { setLoading(true); setErr(null); window.RLX_API.listAdmins(true) .then(res => setAdmins(res.entries || [])) .catch(e => setErr(e.message || 'Failed to load admin accounts')) .finally(() => setLoading(false)); }, []); useEffect(() => { loadAdmins(); }, [loadAdmins]); const submitCreate = async (e) => { e.preventDefault(); if (createForm.password.length < 12) { alert('Password must be at least 12 characters.'); return; } setCreating(true); try { await window.RLX_API.createAdmin(createForm.email.trim(), createForm.password, createForm.role); setCreateOpen(false); setCreateForm({ email: '', password: '', role: 'admin' }); loadAdmins(); } catch (ex) { alert('Failed to create admin: ' + (ex.message || 'error')); } finally { setCreating(false); } }; const toggleActive = async (admin) => { const nextActive = !admin.is_active; if (!nextActive && admin.id === currentAdminId) { alert('You cannot deactivate your own active admin account.'); return; } if (!confirm(`Are you sure you want to ${nextActive ? 'reactivate' : 'deactivate'} ${admin.email}?`)) return; setActionBusy(true); try { await window.RLX_API.patchAdmin(admin.id, { is_active: nextActive }); loadAdmins(); } catch (ex) { alert('Action failed: ' + (ex.message || 'error')); } finally { setActionBusy(false); } }; const submitPasswordReset = async (e) => { e.preventDefault(); if (!pwdModal || pwdModal.password.length < 12) { alert('Password must be at least 12 characters.'); return; } setActionBusy(true); try { await window.RLX_API.patchAdmin(pwdModal.admin.id, { password: pwdModal.password }); setPwdModal(null); alert('Password updated successfully.'); } catch (ex) { alert('Password reset failed: ' + (ex.message || 'error')); } finally { setActionBusy(false); } }; return (

S /Staff Console Accounts

{err &&
{err}
}
{loading && } {!loading && admins.map(a => ( ))}
ID Email Role Status Last Login Created Actions
Loading staff accounts…
{a.id} {a.email} {a.id === currentAdminId && YOU} {a.role} {a.is_active ? active : inactive} {(a.last_login_at || 'never').replace('T', ' ').slice(0, 16)} {(a.created_at || '').slice(0, 10)}
{a.id !== currentAdminId && ( )}
{/* Create Admin Modal */} {createOpen && (
!creating && setCreateOpen(false)}>
e.stopPropagation()} style={{maxWidth: 420}}>
Onboard Staff Admin Account
Email Address
setCreateForm({...createForm, email: e.target.value})} placeholder="colleague@optrl.lab" style={{width: '100%', padding: 8, fontFamily: 'var(--mono)', fontSize: 12, marginBottom: 10}} />
Password (min 12 chars)
setCreateForm({...createForm, password: e.target.value})} placeholder="••••••••••••" style={{width: '100%', padding: 8, fontFamily: 'var(--mono)', fontSize: 12, marginBottom: 10}} />
Role
)} {/* Reset Password Modal */} {pwdModal && (
!actionBusy && setPwdModal(null)}>
e.stopPropagation()} style={{maxWidth: 420}}>
Reset Password · {pwdModal.admin.email}
New Password (min 12 chars):
setPwdModal({...pwdModal, password: e.target.value})} placeholder="••••••••••••" style={{width: '100%', padding: 8, fontFamily: 'var(--mono)', fontSize: 12, marginBottom: 14}} />
)}
); }; // ============================================================ // DOCS // ============================================================ const Docs = ({ onNav, setAlgo, setEnvId }) => { const D = window.RLX_DATA; const apply = (algoName, envId) => { setAlgo(algoName); if (envId) setEnvId(envId); // Straight to the real, API-backed Playground. window.location.href = envId ? ('/dashboard/?env=' + encodeURIComponent(envId)) : '/dashboard/'; }; const guide = [ { key: 'policy', title: 'On-Policy RL', subtitle: 'PPO · TRPO · GRPO', when: 'You have a fast simulator and want stable, reliable improvement. The agent only learns from data collected by its current policy.', avoid: 'Sample-expensive environments, you will throw away every rollout after one gradient step.', operational: 'Good first pick for the Warehouse & Inventory envs if you can afford millions of steps.', picks: [ { algo: 'PPO', env: 'warehouse', label: 'PPO on Warehouse' }, { algo: 'GRPO', env: 'inventory', label: 'GRPO on Inventory' }, ], }, { key: 'value', title: 'Off-Policy RL', subtitle: 'SAC · DreamerV3 · TD-MPC2 · Rainbow-DQN', when: 'Rollouts are expensive and you want sample-efficiency. Replay buffer lets you reuse every transition.', avoid: 'Environments with very sparse rewards and no demonstrations, exploration can stall.', operational: 'Strong default for Truck & Portfolio where each rollout is slow and you want every transition to count.', picks: [ { algo: 'SAC', env: 'portfolio', label: 'SAC on Portfolio' }, { algo: 'DreamerV3', env: 'truck', label: 'DreamerV3 on Truck' }, ], }, { key: 'irl', title: 'Inverse RL / Imitation', subtitle: 'GAIL · AIRL', when: 'You have expert demonstrations but no reward function, or your reward is hard to specify correctly.', avoid: 'You have no demonstrations, or your experts are noisy & inconsistent.', operational: 'Pick this when you already have a human dispatcher’s historical decisions (e.g. truck routes).', picks: [ { algo: 'GAIL', env: 'warehouse', label: 'GAIL on Warehouse (40 demos)' }, { algo: 'AIRL', env: 'truck', label: 'AIRL on Truck' }, ], }, { key: 'offline', title: 'Offline RL', subtitle: 'CQL · IQL · Decision Transformer', when: 'You cannot interact with the environment at all, only a fixed logged dataset. Common for finance, healthcare, industrial control.', avoid: 'Your dataset is small, or very off-distribution from the policy you actually want to deploy.', operational: 'The Portfolio env has 10y of logged trades, start here before ever going online.', picks: [ { algo: 'CQL', env: 'portfolio', label: 'CQL on Portfolio' }, { algo: 'IQL', env: 'inventory', label: 'IQL on Inventory' }, { algo: 'Decision Transformer', env: 'portfolio', label: 'DT on Portfolio' }, ], }, ]; return (

Docs// how ranking works & when to use what

A quick operator’s guide to choosing an algorithm family, plus how our benchmarks, stability, and sim-to-real gap are computed. Click any “apply in playground” to jump straight into a run and see the difference.

01 /When to use what

four families · pick by data regime, not by hype
{guide.map(g => (
{g.title}
{g.subtitle}
Use if
{g.when}
Avoid if
{g.avoid}
Ops note
{g.operational}
Apply in playground →
{g.picks.map(p => ( ))}
))}
Rule of thumb
Pick by the data regime you actually have, not by the paper that came out last week. Logged data only → offline. Demos only → IRL. Cheap sim → on-policy. Expensive sim → off-policy.

02 /How ranking works

{[ { t: 'Ranking', b: 'Mean normalized return over a fixed env suite, averaged across 5 seeds. Ties broken by stability (lower std preferred).' }, { t: 'Stability σ', b: '1 − normalized std across seeds on the same (algo × env) cell. Values closer to 1.0 indicate tighter seed-to-seed reproducibility.' }, { t: 'Sim→Real Gap ★', b: 'OptRL-exclusive. Score delta between in-distribution eval and a fixed bank of Out-Of-Set random scenarios that perturb dynamics, sensors, and task params.' }, { t: 'Community submissions', b: 'Playground runs accepted with a verified X/Twitter handle. Submissions without handles enter the flagged queue for admin review.' }, { t: 'Proprietary ingestion', b: 'OptRL admins upload CSV/XLSX sheets. Schema validation runs server-side; published sheets are versioned and reversible.' }, { t: 'Environments', b: 'MuJoCo, D4RL, Atari, Procgen, DMC for research; OptRL/* for operational envs (Warehouse, Inventory, Portfolio, Truck).' }, ].map((s, i) => (
{String(i+1).padStart(2,'0')} · {s.t}

{s.b}

))}
); }; Object.assign(window, { Home, Admin, Docs });