@@ -50,3 +50,130 @@ def test_plain_optimization_ui_best_respects_minimize_goal():
5050
5151 assert any ("best so far: 1.5" in line for line in lines )
5252 assert any ("Best metric value: 1.5" in line for line in lines )
53+
54+
55+ def _make_plain_ui_with_capture () -> tuple [PlainOptimizationUI , list [str ]]:
56+ """Construct a PlainOptimizationUI that records output to a list instead of stdout."""
57+ ui = PlainOptimizationUI (
58+ run_id = "run-1" ,
59+ run_name = "demo" ,
60+ total_steps = 5 ,
61+ dashboard_url = "https://example.com" ,
62+ model = "gpt-4" ,
63+ metric_name = "accuracy" ,
64+ )
65+ lines : list [str ] = []
66+ ui ._print = lines .append
67+ return ui , lines
68+
69+
70+ def test_plain_ui_on_init_prints_header ():
71+ """on_init prints the run banner exactly once. (Header used to be printed
72+ by __enter__; the move to on_init keeps the same observable behavior for
73+ non-derived runs.)"""
74+ ui , lines = _make_plain_ui_with_capture ()
75+
76+ ui .on_init ()
77+
78+ output = "\n " .join (lines )
79+ assert "WECO OPTIMIZATION RUN" in output
80+ assert "Run ID: run-1" in output
81+ assert "Run Name: demo" in output
82+ assert "Dashboard: https://example.com" in output
83+ assert "Model: gpt-4" in output
84+ assert "Metric: accuracy" in output
85+ assert "Total Steps: 5" in output
86+ # Non-derived run: no "Derived from" line
87+ assert not any ("Derived from" in line for line in lines )
88+
89+
90+ def test_plain_ui_on_init_includes_derived_from_line ():
91+ ui , lines = _make_plain_ui_with_capture ()
92+
93+ ui .on_init (derived_from = {"run_id" : "parent-uuid" , "node_id" : "node-uuid" , "step" : 7 , "metric_value" : 0.842 })
94+
95+ derived_lines = [line for line in lines if "Derived from" in line ]
96+ assert len (derived_lines ) == 1
97+ assert "parent-uuid" in derived_lines [0 ]
98+ assert "step 7" in derived_lines [0 ]
99+ assert "0.842" in derived_lines [0 ]
100+
101+
102+ def test_plain_ui_on_init_handles_derived_from_without_metric ():
103+ """A node with no metric_value (e.g., still pending eval) shouldn't crash
104+ the header rendering."""
105+ ui , lines = _make_plain_ui_with_capture ()
106+
107+ ui .on_init (derived_from = {"run_id" : "parent-uuid" , "node_id" : "node-uuid" , "step" : 0 , "metric_value" : None })
108+
109+ derived_lines = [line for line in lines if "Derived from" in line ]
110+ assert len (derived_lines ) == 1
111+ assert "parent-uuid" in derived_lines [0 ]
112+ assert "step 0" in derived_lines [0 ]
113+ # No "(metric: ...)" suffix when metric_value is None. Specific to the
114+ # suffix's literal form so the assertion is robust to metric_name values
115+ # that happen to contain the substring "metric".
116+ assert "(metric:" not in derived_lines [0 ]
117+
118+
119+ def test_plain_ui_enter_no_longer_prints_header ():
120+ """Header printing must happen via on_init now, not __enter__. This guards
121+ against accidentally re-introducing the auto-print and double-printing the
122+ header."""
123+ ui , lines = _make_plain_ui_with_capture ()
124+
125+ with ui :
126+ pass
127+
128+ assert lines == []
129+
130+
131+ def test_live_ui_on_init_renders_derived_from_row ():
132+ """The Live panel grid gains a "From" row when derived_from is set."""
133+ ui = LiveOptimizationUI (
134+ console = Console (force_terminal = False , color_system = None ),
135+ run_id = "run-1" ,
136+ run_name = "demo" ,
137+ total_steps = 3 ,
138+ dashboard_url = "https://example.com" ,
139+ metric_name = "accuracy" ,
140+ )
141+
142+ ui .on_init (derived_from = {"run_id" : "parent-uuid" , "node_id" : "node-uuid" , "step" : 4 , "metric_value" : 0.91 })
143+
144+ text = _render_to_text (ui ._render ())
145+ assert "parent-uuid" in text
146+ assert "step 4" in text
147+ assert "0.91" in text
148+
149+
150+ def test_live_ui_on_init_without_derived_from_does_not_render_from_row ():
151+ """Negative cousin to test_live_ui_on_init_renders_derived_from_row.
152+
153+ Renders the same UI both with and without ``derived_from`` and asserts
154+ the parent reference (the marker added by the "From" row) appears only
155+ in the derived render. Comparing the two renders directly avoids
156+ fragile substring checks against unrelated panel chrome.
157+ """
158+
159+ def render (derived_from ):
160+ ui = LiveOptimizationUI (
161+ console = Console (force_terminal = False , color_system = None ),
162+ run_id = "run-1" ,
163+ run_name = "demo" ,
164+ total_steps = 3 ,
165+ dashboard_url = "https://example.com" ,
166+ )
167+ ui .on_init (derived_from = derived_from )
168+ return _render_to_text (ui ._render ())
169+
170+ derived_text = render ({"run_id" : "parent-uuid" , "node_id" : "n" , "step" : 4 , "metric_value" : 0.91 })
171+ plain_text = render (None )
172+
173+ # The parent reference is added only by the "From" row, so its presence
174+ # in one render and absence in the other proves the row is conditional.
175+ assert "parent-uuid" in derived_text
176+ assert "parent-uuid" not in plain_text
177+ # Belt and braces: the row label itself only appears in the derived
178+ # render (no other panel label contains "From" as a substring).
179+ assert "From" not in plain_text
0 commit comments