@@ -117,11 +117,14 @@ def test_search_endpoint_calls_bubble_from_dict(self):
117117
118118 def test_workspace_tabs_endpoint_calls_bubble_from_dict (self ):
119119 from app import create_app
120- import api .workspaces as workspaces_mod
120+ import services .workspace_db as workspace_db_mod
121+ from models import Bubble
121122 app = create_app ()
122123 app .config ["TESTING" ] = True
123124 app .config ["EXCLUSION_RULES" ] = []
124- with patch .object (workspaces_mod .Bubble , "from_dict" , wraps = workspaces_mod .Bubble .from_dict ) as spy :
125+ with patch .object (
126+ workspace_db_mod .Bubble , "from_dict" , wraps = Bubble .from_dict
127+ ) as spy :
125128 client = app .test_client ()
126129 response = client .get (f"/api/workspaces/{ WORKSPACE_ID } /tabs" )
127130 self .assertEqual (response .status_code , 200 )
@@ -136,8 +139,6 @@ def test_bubble_schema_drift_is_logged_not_swallowed_silently(self):
136139 # ValueError and skipped silently. Schema drift must now log a
137140 # `Schema drift in bubble <bid>` line so disappearing bubbles can be
138141 # traced. The well-formed row still loads alongside.
139- import logging
140-
141142 from app import create_app
142143 # Seed a deliberately-malformed bubble row that will trip
143144 # Bubble.from_dict's "expected non-empty str" gate on the bubble_id by
@@ -163,17 +164,20 @@ def test_bubble_schema_drift_is_logged_not_swallowed_silently(self):
163164 msg = "drift log must include the offending bubble id" )
164165
165166 def test_workspace_tabs_endpoint_calls_composer_from_dict (self ):
166- # Brad's most-important finding: list_workspaces() at api/workspaces.py:605
167- # validates each composer with Composer.from_dict, but get_workspace_tabs()
168- # in the same file used raw json.loads. Schema drift would have been hidden
169- # from one of the two primary conversation-browsing paths. This test pins
170- # that BOTH paths must now validate via the model.
167+ # Brad's most-important finding: list_workspaces() validates each composer
168+ # with Composer.from_dict, but get_workspace_tabs() used raw json.loads.
169+ # Schema drift would have been hidden from one of the two primary
170+ # conversation-browsing paths. This test pins that BOTH paths must now
171+ # validate via the model.
171172 from app import create_app
172- import api .workspaces as workspaces_mod
173+ import services .workspace_tabs as workspace_tabs_mod
174+ from models import Composer
173175 app = create_app ()
174176 app .config ["TESTING" ] = True
175177 app .config ["EXCLUSION_RULES" ] = []
176- with patch .object (workspaces_mod .Composer , "from_dict" , wraps = workspaces_mod .Composer .from_dict ) as spy :
178+ with patch .object (
179+ workspace_tabs_mod .Composer , "from_dict" , wraps = Composer .from_dict
180+ ) as spy :
177181 client = app .test_client ()
178182 response = client .get (f"/api/workspaces/{ WORKSPACE_ID } /tabs" )
179183 self .assertEqual (response .status_code , 200 )
@@ -220,8 +224,13 @@ def test_composers_endpoint_calls_workspace_from_dict(self):
220224
221225 def test_workspace_display_name_calls_workspace_from_dict (self ):
222226 from services .workspace_resolver import lookup_workspace_display_name
223- import api .workspaces as workspaces_mod
224- with patch .object (workspaces_mod .Workspace , "from_dict" , wraps = workspaces_mod .Workspace .from_dict ) as spy :
227+ import services .workspace_resolver as workspace_resolver_mod
228+ from models import Workspace
229+ with patch .object (
230+ workspace_resolver_mod .Workspace ,
231+ "from_dict" ,
232+ wraps = Workspace .from_dict ,
233+ ) as spy :
225234 name = lookup_workspace_display_name (self .workspace_path , WORKSPACE_ID )
226235 self .assertIsInstance (name , str )
227236 self .assertGreaterEqual (
0 commit comments