Spaces:
Running on Zero
Running on Zero
| """The rendering layer: the design ports faithfully, and stays capability-gated. | |
| Two classes of test here. | |
| *Fidelity*: every stylesheet the design system ships actually reaches the page, | |
| and nothing forces height from `vh` (which ratchets the Spaces iframe). These | |
| catch the failure where the app looks approximately right in a way that is hard | |
| to name. | |
| *Gating*: the UI decides what to draw from an adapter's declared capabilities | |
| and never from a model's name. The fixture adapters below exist so that claim | |
| can be tested without loading a single weight. | |
| """ | |
| from __future__ import annotations | |
| import re | |
| import numpy as np | |
| import pandas as pd | |
| import pytest | |
| from src import config, view | |
| from src.adapters.base import (OUTPUT_OHLCV_PATHS, OUTPUT_QUANTILE_LINE, | |
| Capabilities, ForecastAdapter, ForecastResult) | |
| from src.ui import chart, chrome, shell | |
| from tests.fixture import future_ts, synth | |
| from bit_ui import theme | |
| # -------------------------------------------------------------------------- | |
| # Fixture adapters -- declared capabilities, no weights | |
| # -------------------------------------------------------------------------- | |
| class _Fixture(ForecastAdapter): | |
| """An adapter that declares whatever the test needs it to.""" | |
| family = "fixture" | |
| def __init__(self, output=OUTPUT_QUANTILE_LINE, hardware="cpu"): | |
| super().__init__("fixture/model", revision="test") | |
| self._output, self._hardware = output, hardware | |
| def capabilities(self): | |
| return Capabilities(output=self._output, hardware=self._hardware, | |
| max_context=256) | |
| def load(self, model_id=None, revision=None): | |
| self._model = True | |
| self._resolved_revision = "test" | |
| return self | |
| def predict(self, context_ohlcv, horizon=6, n_samples=8, seed=0, | |
| issued_ts=None): | |
| last = float(context_ohlcv["close"].iloc[-1]) | |
| q = np.tile(np.array([0.97, 0.99, 1.0, 1.01, 1.03]) * last, (horizon, 1)) | |
| paths = None | |
| if self._output == OUTPUT_OHLCV_PATHS: | |
| paths = np.tile(last, (n_samples, horizon, 5)).astype("float64") | |
| return ForecastResult( | |
| quantiles=q, levels=config.QUANTILE_LEVELS, horizon=horizon, | |
| context_len=len(context_ohlcv), inference_version="fixture", | |
| seed=seed, n_samples=n_samples, paths=paths) | |
| class _Run: | |
| """The shape `shell` expects from `runtime.ForecastRun`.""" | |
| def __init__(self, adapter, context, horizon=6, slug="fixture"): | |
| self.model_slug = slug | |
| self.model_id = "fixture/model" | |
| self.family = "fixture" | |
| self.asset, self.timeframe, self.horizon = "BTC-USD", "1h", horizon | |
| self.context = context | |
| self.result = adapter.predict(context, horizon=horizon) | |
| self.issued_ts = pd.to_datetime(context["ts"], utc=True).iloc[-1] | |
| self.target_ts = future_ts(context, horizon) | |
| self.capabilities = adapter.capabilities().as_dict() | |
| self.forecast_id, self.archived_rows, self.elapsed_s = "fid", horizon, 0.1 | |
| def _data(runs, state, **over): | |
| models = [{ | |
| "slug": r.model_slug, "name": r.model_slug, "family": "fixture", | |
| "size": "1M", "caps": r.capabilities, "color": "var(--accent-amber-strong)", | |
| "grade": "-", "grade_color": "var(--text-tertiary)", | |
| "resolved_label": "UNRESOLVED", | |
| } for r in runs] or [{ | |
| "slug": "fixture", "name": "fixture", "family": "fixture", "size": "1M", | |
| "caps": {"output": OUTPUT_QUANTILE_LINE, "hardware": "cpu"}, | |
| "color": "var(--accent-amber-strong)", "grade": "-", | |
| "grade_color": "var(--text-tertiary)", "resolved_label": "UNRESOLVED"}] | |
| data = { | |
| "models": models, | |
| "models_by_slug": {m["slug"]: m for m in models}, | |
| "panels": {r.model_slug: {"empty": True} for r in runs}, | |
| "runs": runs, | |
| "chart": (chart.build(runs[0].context, runs, "BTC-USD", runs[0].horizon) | |
| if runs else {}), | |
| "volatility": {"rows": [], "verdict": "", "note": ""}, | |
| "stats": [], "standings_rows": [], "families": ("kronos",), | |
| "coverage": {"scope": "", "pct_label": "—", "pct_width": "0%", "rows": []}, | |
| "nav": {}, "archived_total": 0, "resolved_total": 0, | |
| "resolver_last_ran": "NEVER", "runtime_hint": "~1S", | |
| "quota_blocked": False, "footer_resources": (), "status_line": "", | |
| "error": None, | |
| } | |
| data.update(over) | |
| return data | |
| def context(): | |
| return synth(300) | |
| def _state(**over): | |
| state = view.default_state() | |
| state["selected"] = ["fixture"] | |
| state.update(over) | |
| return state | |
| # -------------------------------------------------------------------------- | |
| # 6. Capability gating (fixture adapter) | |
| # -------------------------------------------------------------------------- | |
| def test_quantile_model_never_reaches_the_ghost_path_code(context): | |
| adapter = _Fixture(output=OUTPUT_QUANTILE_LINE).load() | |
| run = _Run(adapter, context) | |
| html = shell.chart_section(_state(), _data([run], _state())) | |
| assert "Quantile line only" in html | |
| assert "Sampled OHLCV paths" not in html | |
| # The ghost renderer's own opacity value must appear nowhere. | |
| assert 'opacity="0.17"' not in html | |
| def test_path_model_gets_the_ghost_control_and_the_ghosts(context): | |
| adapter = _Fixture(output=OUTPUT_OHLCV_PATHS).load() | |
| run = _Run(adapter, context) | |
| html = shell.chart_section(_state(ghosts=True), _data([run], _state())) | |
| assert "Sampled OHLCV paths" in html | |
| assert "Quantile line only" not in html | |
| def test_ghosts_are_suppressed_when_the_toggle_is_off(context): | |
| adapter = _Fixture(output=OUTPUT_OHLCV_PATHS).load() | |
| run = _Run(adapter, context) | |
| drawing = chart.build(context, [run], "BTC-USD", run.horizon, show_ghosts=False) | |
| assert 'opacity="0.17"' not in drawing["svg"] | |
| drawing_on = chart.build(context, [run], "BTC-USD", run.horizon, show_ghosts=True) | |
| assert 'opacity="0.17"' in drawing_on["svg"] | |
| def test_chart_ignores_paths_when_the_capability_does_not_declare_them(context): | |
| """A result carrying paths but declaring `quantile_line` draws no ghosts. | |
| This is the gate that matters: rendering keys off the declaration, not off | |
| whether the array happens to be populated. | |
| """ | |
| adapter = _Fixture(output=OUTPUT_OHLCV_PATHS).load() | |
| run = _Run(adapter, context) | |
| assert run.result.paths is not None | |
| run.capabilities = {"output": OUTPUT_QUANTILE_LINE, "hardware": "cpu"} | |
| drawing = chart.build(context, [run], "BTC-USD", run.horizon, show_ghosts=True) | |
| assert 'opacity="0.17"' not in drawing["svg"] | |
| def test_hardware_capability_drives_the_cpu_gpu_chip(context): | |
| for hardware, expected in (("cpu", "CPU · instant"), ("gpu", "your GPU quota")): | |
| adapter = _Fixture(hardware=hardware).load() | |
| run = _Run(adapter, context) | |
| html = shell.models_section(_state(), _data([run], _state())) | |
| assert expected in html | |
| def test_no_model_family_is_named_in_the_rendering_layer(): | |
| """The UI must not special-case a model by name. | |
| Capability flags are the whole interface between adapters and rendering; | |
| a name check here is how that boundary rots. | |
| """ | |
| import pathlib | |
| for name in ("shell.py", "chart.py"): | |
| source = (pathlib.Path(__file__).resolve().parents[1] | |
| / "src" / "ui" / name).read_text().lower() | |
| # Prose in docstrings is fine; a comparison against a model name is not. | |
| for family in ("kronos", "chronos", "timesfm"): | |
| assert f'== "{family}' not in source | |
| assert f"'{family}'" not in source.replace("'kronos, chronos or timesfm'", "") | |
| # -------------------------------------------------------------------------- | |
| # Design fidelity | |
| # -------------------------------------------------------------------------- | |
| def test_every_design_system_stylesheet_reaches_the_page(): | |
| """Keyed on a rule only that file contains. | |
| Vendoring the token files and forgetting `base.css` is the classic version | |
| of this bug: the app inherits the framework's rounded corners and roomy | |
| padding and looks approximately right in a way nobody can name. | |
| """ | |
| css = chrome.full_css() | |
| markers = { | |
| "colors.css": "--bg-canvas", | |
| "typography.css": "--text-2xs", | |
| "spacing.css": "--tracking-wider", | |
| "base.css": "user-select", | |
| } | |
| for filename, marker in markers.items(): | |
| assert marker in css, f"{filename} did not reach the page ({marker} missing)" | |
| def test_arena_css_reaches_the_page_too(): | |
| """`theme.full_css()` alone would silently drop the Arena's own rules.""" | |
| css = chrome.full_css() | |
| for marker in (".fa-rail", ".fa-picker", ".fa-card", ".fa-chart"): | |
| assert marker in css | |
| def test_nothing_forces_height_from_vh(context): | |
| """`height:100vh` inside the Spaces iframe ratchets the page height.""" | |
| adapter = _Fixture(output=OUTPUT_OHLCV_PATHS).load() | |
| run = _Run(adapter, context) | |
| state = _state() | |
| html = shell.page(state, _data([run], state)) | |
| offenders = theme.find_forced_vh(html) | |
| assert not offenders, f"forced vh heights: {offenders}" | |
| def test_chart_uses_the_designs_geometry(context): | |
| adapter = _Fixture().load() | |
| run = _Run(adapter, context) | |
| svg = chart.build(context, [run], "BTC-USD", run.horizon)["svg"] | |
| assert 'viewBox="0 0 1200 352"' in svg | |
| def test_interpolated_values_are_escaped(context): | |
| """Model ids and user text reach the markup; they must not become markup.""" | |
| state = _state(hfid='"><script>alert(1)</script>') | |
| html = shell._enroll(state, _data([], state)) | |
| assert "<script>alert(1)" not in html | |
| assert "<script>" in html or "">" in html | |
| # -------------------------------------------------------------------------- | |
| # 9. Error states | |
| # -------------------------------------------------------------------------- | |
| def test_designed_error_states_render(kind, needle): | |
| state = _state() | |
| err = {"kind": kind, "title": "Something went wrong", | |
| "message": "the detail", "login_url": "#", "duplicate_url": "#"} | |
| html = shell.chart_section(state, _data([], state, error=err)) | |
| assert needle in html | |
| assert "the detail" in html | |
| assert "DISMISS" in html | |
| def test_quota_banner_renders_when_blocked(): | |
| state = _state() | |
| html = shell.controls(state, _data([], state, quota_blocked=True, | |
| quota_msg="GPU-tier model — sign in", | |
| runtime_hint="BLOCKED")) | |
| assert "GPU-tier model" in html | |
| assert "BLOCKED" in html | |
| def test_rejected_enrollment_renders_its_message(): | |
| state = _state(enroll_ok=False, | |
| enroll_note="'nope' is not a supported adapter family.") | |
| html = shell._enroll(state, _data([], state)) | |
| assert "not a supported adapter family" in html | |
| assert "var(--fin-down)" in html | |
| def test_empty_track_record_renders_the_designed_state(): | |
| state = _state() | |
| html = shell.trackrecord_section(state, _data([], state)) | |
| assert "No history yet" in html | |
| assert "MAKE THE FIRST FORECAST" in html | |
| # -------------------------------------------------------------------------- | |
| # Bridge | |
| # -------------------------------------------------------------------------- | |
| def test_actions_off_the_allow_list_are_dropped(): | |
| assert chrome.parse_action("definitely-not-an-action:1|n") is None | |
| assert chrome.parse_action("run:go|n1") is not None | |
| def test_emit_refuses_an_action_it_does_not_know(): | |
| with pytest.raises(Exception): | |
| chrome.emit("not-a-real-action", "x") | |
| def test_sidebar_collapse_is_not_a_server_action(): | |
| """Routing it through Gradio would re-render the whole page to move a rail.""" | |
| assert "sidebar" not in chrome.ALLOWED_KEYS | |
| # -------------------------------------------------------------------------- | |
| # The bridge actually reaches the markup | |
| # -------------------------------------------------------------------------- | |
| def test_every_control_carries_a_real_data_bit_attribute(context): | |
| """Regression: `emit()` returns the attribute *value*, not the attribute. | |
| Interpolating it bare renders `<button run:go>` -- an unknown attribute, | |
| no `data-bit`, so the delegated listener never matches and every control on | |
| the page silently does nothing. Nothing else in the suite caught that, | |
| because the markup was still well-formed and still contained the action | |
| strings. This asserts the attribute, not the string. | |
| """ | |
| adapter = _Fixture(output=OUTPUT_OHLCV_PATHS).load() | |
| run = _Run(adapter, context) | |
| state = _state() | |
| html = shell.page(state, _data([run], state)) | |
| buttons = re.findall(r"<button\b[^>]*>", html) | |
| assert len(buttons) > 12, f"only {len(buttons)} buttons rendered" | |
| # The sidebar toggle is the one deliberate exception: collapsing is a | |
| # client-side class flip (`data-bit-sidebar-toggle`), never a server | |
| # action, because routing it through Gradio would re-render the whole page | |
| # to move a rail 160px. | |
| without = [b for b in buttons | |
| if "data-bit=" not in b and "data-bit-sidebar-toggle" not in b] | |
| assert not without, f"buttons with no data-bit: {without[:3]}" | |
| # And the actions that reach it must be ones the bridge accepts. | |
| for value in re.findall(r'data-bit="([^"]+)"', html): | |
| assert chrome.parse_action(f"{value}|nonce") is not None, \ | |
| f"{value!r} would be dropped by the bridge" | |
| def test_the_run_control_is_present_and_addressable(context): | |
| """The single most important control on the page.""" | |
| state = _state() | |
| html = shell.controls(state, _data([], state)) | |
| assert 'data-bit="run:go"' in html | |
| def test_the_no_gpu_state_offers_the_only_thing_that_helps(): | |
| """On CPU hardware a GPU-tier model cannot be made to work by waiting.""" | |
| state = _state() | |
| err = {"kind": "no_gpu", "title": "GPU hardware not attached", | |
| "message": "kronos-small needs GPU hardware.", | |
| "duplicate_url": "https://example.invalid?duplicate=true"} | |
| html = shell.chart_section(state, _data([], state, error=err)) | |
| assert "RUN IT ON YOUR OWN HARDWARE" in html | |
| assert "needs GPU hardware" in html | |
| def test_matchup_draws_fans_but_never_ghosts(context): | |
| """Three models' sampled paths over one another is a smear. | |
| The design gates ghosts on playground mode as well as on capability, and | |
| the chart panel already hides the toggle in matchup -- but the drawing call | |
| has to agree, or the ghosts render with no way to turn them off. | |
| """ | |
| adapter = _Fixture(output=OUTPUT_OHLCV_PATHS).load() | |
| runs = [_Run(adapter, context, slug=f"m{i}") for i in range(3)] | |
| state = _state(mode="matchup", selected=[r.model_slug for r in runs], | |
| ghosts=True) | |
| html = shell.chart_section(state, _data(runs, state)) | |
| assert "Sampled OHLCV paths" not in html, "ghost toggle offered in matchup" | |
| drawing = chart.build(context, runs, "BTC-USD", runs[0].horizon, | |
| show_ghosts=False) | |
| assert 'opacity="0.17"' not in drawing["svg"] | |
| # -------------------------------------------------------------------------- | |
| # Cached forecasts must be labelled as cached | |
| # -------------------------------------------------------------------------- | |
| def _cached(run): | |
| run.from_cache = True | |
| return run | |
| def test_a_cached_forecast_says_when_it_was_made(context): | |
| adapter = _Fixture(output=OUTPUT_QUANTILE_LINE).load() | |
| run = _cached(_Run(adapter, context)) | |
| state = _state() | |
| html = shell.chart_section(state, _data([run], state)) | |
| assert "LAST ARCHIVED" in html | |
| assert "ISSUED" in html | |
| assert "FROZEN" in html | |
| def test_a_freshly_issued_forecast_is_not_labelled_archived(context): | |
| adapter = _Fixture(output=OUTPUT_QUANTILE_LINE).load() | |
| run = _Run(adapter, context) # from_cache defaults to False | |
| state = _state() | |
| html = shell.chart_section(state, _data([run], state)) | |
| assert "LAST ARCHIVED" not in html | |
| def test_a_cached_backfill_says_so(context): | |
| adapter = _Fixture(output=OUTPUT_QUANTILE_LINE).load() | |
| run = _cached(_Run(adapter, context)) | |
| run.backfilled = True | |
| state = _state() | |
| assert "BACKFILL" in shell.chart_section(state, _data([run], state)) | |
| def test_a_path_model_with_no_archived_paths_says_why_it_is_empty(context): | |
| """Offering a toggle that draws nothing is worse than explaining.""" | |
| adapter = _Fixture(output=OUTPUT_OHLCV_PATHS).load() | |
| run = _cached(_Run(adapter, context)) | |
| run.result.paths = None # archived before paths were stored | |
| state = _state(ghosts=True) | |
| html = shell.chart_section(state, _data([run], state)) | |
| assert "Paths not archived" in html | |
| assert "Sampled OHLCV paths" not in html, "offered a toggle with nothing to draw" | |
| def test_a_path_model_with_archived_paths_still_offers_the_toggle(context): | |
| adapter = _Fixture(output=OUTPUT_OHLCV_PATHS).load() | |
| run = _cached(_Run(adapter, context)) | |
| assert run.result.paths is not None | |
| state = _state(ghosts=True) | |
| html = shell.chart_section(state, _data([run], state)) | |
| assert "Sampled OHLCV paths" in html | |
| assert "Paths not archived" not in html | |
| def test_age_reads_in_the_coarsest_honest_unit(delta, expected): | |
| now = pd.Timestamp("2026-08-21T12:00:00Z") | |
| assert view.age_label(now - delta, now=now) == expected | |