fix(imports): break models<->dag_engine circular dependency
Track.get_executable_tickets (in models.py) called TrackDAG at runtime, forcing a top-level import of src.dag_engine into models.py and creating a 2-cycle that broke whichever module loaded second (Ticket was not yet defined when models.py loaded first; TrackDAG was not yet defined when dag_engine.py loaded first). Fix: hoist the method out of the Track dataclass and into a free function get_executable_tickets(track) in dag_engine.py. models.py no longer needs TrackDAG at all, so the cycle is one-directional (models -> dag_engine) and resolves cleanly in any import order. Tests updated: - tests/test_mma_models.py: import get_executable_tickets and call it instead of track.get_executable_tickets() (4 call sites) - tests/test_conductor_engine_v2.py: comment update Verified both import orders resolve cleanly: forward: import src.models; import src.dag_engine -> OK reverse: import src.dag_engine; import src.models -> OK 34 tests pass (test_mma_models, test_dag_engine, test_execution_engine, test_arch_boundary_phase3, test_track_state_schema).
This commit is contained in:
+12
-1
@@ -89,7 +89,7 @@ class TrackDAG:
|
||||
Returns a list of tickets that are in 'todo' status and whose dependencies are all 'completed'.
|
||||
Returns:
|
||||
A list of Ticket objects ready for execution.
|
||||
[C: src/models.py:Track.get_executable_tickets, tests/test_dag_engine.py:test_get_ready_tasks_branching, tests/test_dag_engine.py:test_get_ready_tasks_linear, tests/test_dag_engine.py:test_get_ready_tasks_multiple_deps, tests/test_orchestration_logic.py:test_track_executable_tickets]
|
||||
[C: src/dag_engine.py:get_executable_tickets, tests/test_dag_engine.py:test_get_ready_tasks_branching, tests/test_dag_engine.py:test_get_ready_tasks_linear, tests/test_dag_engine.py:test_get_ready_tasks_multiple_deps, tests/test_orchestration_logic.py:test_track_executable_tickets]
|
||||
"""
|
||||
ready = []
|
||||
for ticket in self.tickets:
|
||||
@@ -162,6 +162,17 @@ class TrackDAG:
|
||||
raise ValueError("Dependency cycle detected")
|
||||
return result
|
||||
|
||||
def get_executable_tickets(track: "Track") -> List[Ticket]:
|
||||
"""
|
||||
Convenience: returns the ready-to-execute tickets of a Track.
|
||||
Free function (instead of Track.get_executable_tickets) so that
|
||||
src/models.py does not need to import TrackDAG at module level,
|
||||
breaking the models<->dag_engine circular dependency.
|
||||
[C: tests/test_mma_models.py:test_track_get_executable_tickets, tests/test_mma_models.py:test_track_get_executable_tickets_complex]
|
||||
"""
|
||||
return TrackDAG(track.tickets).get_ready_tasks()
|
||||
|
||||
|
||||
class ExecutionEngine:
|
||||
"""
|
||||
A state machine that governs the progression of tasks within a TrackDAG.
|
||||
|
||||
@@ -341,16 +341,8 @@ class Track:
|
||||
description: str
|
||||
tickets: List[Ticket] = field(default_factory=list)
|
||||
|
||||
def get_executable_tickets(self) -> List[Ticket]:
|
||||
"""
|
||||
[C: tests/test_mma_models.py:test_track_get_executable_tickets, tests/test_mma_models.py:test_track_get_executable_tickets_complex]
|
||||
"""
|
||||
dag = TrackDAG(self.tickets)
|
||||
return dag.get_ready_tasks()
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
"""
|
||||
[C: src/personas.py:PersonaManager.save_persona, src/presets.py:PresetManager.save_preset, src/project_manager.py:save_project, src/project_manager.py:save_track_state, src/tool_presets.py:ToolPresetManager.save_bias_profile, src/tool_presets.py:ToolPresetManager.save_preset, src/workspace_manager.py:WorkspaceManager.save_profile, tests/test_bias_models.py:test_bias_profile_model, tests/test_bias_models.py:test_tool_model, tests/test_bias_models.py:test_tool_preset_extension, tests/test_context_presets_models.py:test_context_preset_serialization, tests/test_context_presets_models.py:test_file_view_preset_serialization, tests/test_custom_slices_annotations.py:test_file_item_custom_slices_round_trip_annotations, tests/test_custom_slices_annotations.py:test_file_item_custom_slices_serialization_with_annotations, tests/test_event_serialization.py:test_user_request_event_serialization, tests/test_external_editor.py:TestExternalEditorConfig.test_to_dict, tests/test_external_editor.py:TestTextEditorConfig.test_to_dict, tests/test_file_item_model.py:test_file_item_to_dict, tests/test_gui_events_v2.py:test_user_request_event_payload, tests/test_history_manager.py:TestHistoryManager.test_snapshot_roundtrip, tests/test_mcp_config.py:test_mcp_configuration_to_from_dict, tests/test_mcp_config.py:test_mcp_server_config_to_from_dict, tests/test_per_ticket_model.py:test_model_override_serialization, tests/test_persona_id.py:test_ticket_persona_id_serialization, tests/test_persona_models.py:test_persona_defaults, tests/test_persona_models.py:test_persona_serialization, tests/test_slice_editor_behavior.py:test_add_slice_with_annotations, tests/test_thinking_gui.py:test_thinking_segment_model_compatibility, tests/test_ticket_queue.py:test_ticket_to_dict_priority, tests/test_tiered_aggregation.py:test_persona_aggregation_strategy, tests/test_track_state_schema.py:test_track_state_to_dict, tests/test_track_state_schema.py:test_track_state_to_dict_with_none, tests/test_ui_summary_only_removal.py:test_file_item_serialization_with_flags]
|
||||
"""
|
||||
return {
|
||||
"id": self.id,
|
||||
@@ -361,7 +353,6 @@ class Track:
|
||||
@classmethod
|
||||
def from_dict(cls, data: Dict[str, Any]) -> "Track":
|
||||
"""
|
||||
[C: src/personas.py:PersonaManager.load_all, src/presets.py:PresetManager.load_all, src/project_manager.py:load_project, src/project_manager.py:load_track_state, src/tool_presets.py:ToolPresetManager.load_all_bias_profiles, src/tool_presets.py:ToolPresetManager.load_all_presets, src/workspace_manager.py:WorkspaceManager.load_all_profiles, tests/test_bias_models.py:test_bias_profile_model, tests/test_bias_models.py:test_tool_model, tests/test_bias_models.py:test_tool_preset_extension, tests/test_context_presets_models.py:test_context_preset_from_dict_legacy, tests/test_context_presets_models.py:test_context_preset_serialization, tests/test_context_presets_models.py:test_file_view_preset_serialization, tests/test_custom_slices_annotations.py:test_file_item_custom_slices_deserialization_with_annotations, tests/test_custom_slices_annotations.py:test_file_item_custom_slices_round_trip_annotations, tests/test_external_editor.py:TestExternalEditorConfig.test_from_dict_with_dict_editors, tests/test_external_editor.py:TestExternalEditorConfig.test_from_dict_with_string_editors, tests/test_external_editor.py:TestTextEditorConfig.test_from_dict_with_diff_args, tests/test_external_editor.py:TestTextEditorConfig.test_from_dict_without_diff_args, tests/test_file_item_model.py:test_file_item_from_dict, tests/test_file_item_model.py:test_file_item_from_dict_defaults, tests/test_history_manager.py:TestHistoryManager.test_snapshot_roundtrip, tests/test_mcp_config.py:test_mcp_configuration_to_from_dict, tests/test_mcp_config.py:test_mcp_server_config_to_from_dict, tests/test_per_ticket_model.py:test_model_override_default_on_deserialize, tests/test_per_ticket_model.py:test_model_override_deserialization, tests/test_persona_id.py:test_ticket_persona_id_deserialization, tests/test_persona_models.py:test_persona_defaults, tests/test_persona_models.py:test_persona_deserialization, tests/test_project_serialization.py:TestProjectSerialization.test_backward_compatibility_strings, tests/test_slice_editor_behavior.py:test_add_slice_with_annotations, tests/test_ticket_queue.py:test_ticket_from_dict_default_priority, tests/test_ticket_queue.py:test_ticket_from_dict_priority, tests/test_tiered_aggregation.py:test_persona_aggregation_strategy, tests/test_track_state_schema.py:test_track_state_from_dict, tests/test_track_state_schema.py:test_track_state_from_dict_empty_and_missing, tests/test_ui_summary_only_removal.py:test_file_item_serialization_with_flags]
|
||||
"""
|
||||
return cls(
|
||||
id = data["id"],
|
||||
@@ -938,8 +929,6 @@ class MCPServerConfig:
|
||||
|
||||
#endregion: MCP Config
|
||||
|
||||
from src.dag_engine import TrackDAG
|
||||
|
||||
@dataclass
|
||||
class MCPConfiguration:
|
||||
mcpServers: Dict[str, MCPServerConfig] = field(default_factory=dict)
|
||||
|
||||
Reference in New Issue
Block a user