Private
Public Access
0
0

refactor(consumers): migrate 85 'from src.models import' sites to direct subsystem imports

Per post_module_taxonomy_de_cruft_20260627 Phase 2 (FR7). Each
'from src.models import X' for a moved class is rewritten to
'from src.<destination> import X':

  Ticket, Track, WorkerContext, TrackState, TrackMetadata,
    ThinkingSegment, EMPTY_TRACK_STATE            -> src.mma
  ProjectContext, ProjectMeta, ProjectOutput, ProjectFiles,
    ProjectScreenshots, ProjectDiscussion, EMPTY_PROJECT_CONTEXT -> src.project
  FileItem, Preset, ContextPreset, ContextFileEntry,
    NamedViewPreset                                -> src.project_files
  Tool, ToolPreset                                 -> src.tool_presets
  BiasProfile                                      -> src.tool_bias
  TextEditorConfig, ExternalEditorConfig,
    EMPTY_TEXT_EDITOR_CONFIG                       -> src.external_editor
  Persona                                          -> src.personas
  WorkspaceProfile                                -> src.workspace_manager
  MCPServerConfig, MCPConfiguration, VectorStoreConfig,
    RAGConfig, load_mcp_config                      -> src.mcp_client

NOT touched (kept on src.models; Phase 3 or Phase 4 will move them):
  GenerateRequest, ConfirmRequest, DEFAULT_TOOL_CATEGORIES, Metadata, PROVIDERS

Migration was performed by the one-time script
scripts/tier2/artifacts/post_module_taxonomy_de_cruft_20260627/migrate_imports.py
which uses a class-to-module map and re.sub() to rewrite each
'from src.models import X' line.

Total: 85 import lines rewritten across 71 files.

Note: this commit depends on the v2 SHIPPED work
(origin/tier2/module_taxonomy_refactor_20260627) being merged into
this branch NEXT. On master (without the v2 SHIPPED commits), the
destination modules do not exist and these imports would fail.
This commit is contained in:
2026-06-26 13:34:03 -04:00
parent e14cfb13da
commit 8f11340b38
72 changed files with 266 additions and 85 deletions
@@ -0,0 +1,167 @@
"""One-time migration script: src.models import -> direct subsystem imports.
Per post_module_taxonomy_de_cruft_20260627 Phase 2. Updates 95 consumer
sites that use 'from src.models import X' to use the direct subsystem
import path. Each 'from src.models import X' is rewritten based on the
class mapping:
Ticket, Track, WorkerContext, TrackState, TrackMetadata,
ThinkingSegment, EMPTY_TRACK_STATE -> src.mma
ProjectContext, ProjectMeta, ProjectOutput, ProjectFiles,
ProjectScreenshots, ProjectDiscussion, EMPTY_PROJECT_CONTEXT -> src.project
FileItem, Preset, ContextPreset, ContextFileEntry, NamedViewPreset -> src.project_files
Tool, ToolPreset -> src.tool_presets
BiasProfile -> src.tool_bias
TextEditorConfig, ExternalEditorConfig,
EMPTY_TEXT_EDITOR_CONFIG -> src.external_editor
Persona -> src.personas
WorkspaceProfile -> src.workspace_manager
MCPServerConfig, MCPConfiguration, VectorStoreConfig,
RAGConfig, load_mcp_config -> src.mcp_client
NOT touched (kept on src.models):
GenerateRequest, ConfirmRequest -> Phase 4 (api_hooks.py)
DEFAULT_TOOL_CATEGORIES -> Phase 3 (ai_client.py)
Metadata (the legacy alias) -> kept (re-exported at module level)
PROVIDERS -> kept (lazy __getattr__)
Usage:
uv run python scripts/tier2/artifacts/post_module_taxonomy_de_cruft_20260627/migrate_imports.py
This is a one-time script; it does not run as part of the test suite.
"""
from __future__ import annotations
import re
import sys
from pathlib import Path
CLASS_TO_MODULE: dict[str, str] = {
"Ticket": "mma",
"Track": "mma",
"WorkerContext": "mma",
"TrackState": "mma",
"TrackMetadata": "mma",
"ThinkingSegment": "mma",
"EMPTY_TRACK_STATE": "mma",
"ProjectContext": "project",
"ProjectMeta": "project",
"ProjectOutput": "project",
"ProjectFiles": "project",
"ProjectScreenshots": "project",
"ProjectDiscussion": "project",
"EMPTY_PROJECT_CONTEXT": "project",
"FileItem": "project_files",
"Preset": "project_files",
"ContextPreset": "project_files",
"ContextFileEntry": "project_files",
"NamedViewPreset": "project_files",
"Tool": "tool_presets",
"ToolPreset": "tool_presets",
"BiasProfile": "tool_bias",
"TextEditorConfig": "external_editor",
"ExternalEditorConfig": "external_editor",
"EMPTY_TEXT_EDITOR_CONFIG": "external_editor",
"Persona": "personas",
"WorkspaceProfile": "workspace_manager",
"MCPServerConfig": "mcp_client",
"MCPConfiguration": "mcp_client",
"VectorStoreConfig": "mcp_client",
"RAGConfig": "mcp_client",
"load_mcp_config": "mcp_client",
}
KEEP_ON_MODELS: set[str] = {
"GenerateRequest",
"ConfirmRequest",
"DEFAULT_TOOL_CATEGORIES",
"Metadata",
"PROVIDERS",
}
def migrate_file(path: Path) -> tuple[int, list[str]]:
"""Rewrite 'from src.models import X' lines in path. Returns (count, errors)."""
try:
content = path.read_text(encoding="utf-8")
except (OSError, UnicodeDecodeError) as e:
return 0, [f" {path}: cannot read: {e}"]
original = content
errors: list[str] = []
pattern = re.compile(r"^(\s*)from\s+src\.models\s+import\s+(.+?)$", re.MULTILINE)
def replace(m: re.Match[str]) -> str:
indent = m.group(1)
names_str = m.group(2)
names = [n.strip() for n in names_str.split(",")]
kept: list[str] = []
moved: dict[str, list[str]] = {}
for name in names:
if not name:
continue
if name in KEEP_ON_MODELS:
kept.append(name)
continue
if " as " in name:
orig, alias = [s.strip() for s in name.split(" as ", 1)]
if orig in KEEP_ON_MODELS:
kept.append(name)
continue
if orig in CLASS_TO_MODULE:
target_mod = CLASS_TO_MODULE[orig]
moved.setdefault(target_mod, []).append(name)
else:
errors.append(f" {path}: unknown alias '{name}' (orig={orig})")
kept.append(name)
continue
if name in CLASS_TO_MODULE:
target_mod = CLASS_TO_MODULE[name]
moved.setdefault(target_mod, []).append(name)
else:
errors.append(f" {path}: unknown class '{name}'")
kept.append(name)
if not moved and kept == names:
return m.group(0)
lines: list[str] = []
for mod, names_in_mod in sorted(moved.items()):
lines.append(f"{indent}from src.{mod} import {', '.join(names_in_mod)}")
if kept:
lines.append(f"{indent}from src.models import {', '.join(kept)}")
return "\n".join(lines)
new_content = pattern.sub(replace, content)
if new_content != original:
try:
path.write_text(new_content, encoding="utf-8", newline="")
except OSError as e:
return 0, [f" {path}: cannot write: {e}"]
return len(pattern.findall(original)), []
return 0, []
def main() -> int:
root = Path(".")
src_files = sorted(root.glob("src/*.py")) + sorted(root.glob("tests/*.py"))
total_changed = 0
files_changed = 0
all_errors: list[str] = []
for path in src_files:
count, errors = migrate_file(path)
all_errors.extend(errors)
if count > 0:
files_changed += 1
total_changed += count
print(f" {path}: {count} import line(s) rewritten")
print(f"\nTotal: {total_changed} import line(s) rewritten in {files_changed} file(s)")
if all_errors:
print("\nWarnings:")
for err in all_errors:
print(err)
return 1
return 0
if __name__ == "__main__":
sys.exit(main())
+6 -4
View File
@@ -49,7 +49,9 @@ from src.vendor_capabilities import VendorCapabilities, get_capabilities
# TODO(Ed): Eliminate these?
from src.events import EventEmitter
from src.gemini_cli_adapter import GeminiCliAdapter
from src.models import FileItem, ToolPreset, BiasProfile, Tool
from src.project_files import FileItem
from src.tool_bias import BiasProfile
from src.tool_presets import ToolPreset, Tool
from src.paths import get_credentials_path
from src.tool_bias import ToolBiasEngine
from src.tool_presets import ToolPresetManager
@@ -2561,7 +2563,7 @@ def _send_grok(md_content: str, user_message: str, base_dir: str,
if file_items:
for fi in file_items:
if fi.get("is_image") and fi.get("base64_data"):
from src.models import FileItem as _FIC
from src.project_files import FileItem as _FIC
fi_item = fi if isinstance(fi, _FIC) else _FIC.from_dict(fi)
user_content = f"[IMAGE: {fi_item.path or 'attachment'}]\n{user_content}"
if discussion_history and not history:
@@ -2805,7 +2807,7 @@ def _send_qwen(md_content: str, user_message: str, base_dir: str,
if file_items:
for fi in file_items:
if fi.get("is_image") and fi.get("base64_data"):
from src.models import FileItem as _FIC
from src.project_files import FileItem as _FIC
fi_item = fi if isinstance(fi, _FIC) else _FIC.from_dict(fi)
user_content = f"[IMAGE: {fi_item.path or 'attachment'}]\n{user_content}"
if discussion_history and not history:
@@ -2898,7 +2900,7 @@ def _send_llama(md_content: str, user_message: str, base_dir: str,
if file_items:
for fi in file_items:
if fi.get("is_image") and fi.get("base64_data"):
from src.models import FileItem as _FIC
from src.project_files import FileItem as _FIC
fi_item = fi if isinstance(fi, _FIC) else _FIC.from_dict(fi)
user_content = f"[IMAGE: {fi_item.path or 'attachment'}]\n{user_content}"
if discussion_history and not history:
+1 -1
View File
@@ -101,7 +101,7 @@ def generate_tickets(track_brief: str, module_skeletons: str) -> list[dict[str,
ai_client.set_current_tier(None)
from src.dag_engine import TrackDAG
from src.models import Ticket
from src.mma import Ticket
from src.result_types import ErrorInfo, ErrorKind, Result
def topological_sort(tickets: list[Ticket]) -> list[Ticket]:
+1 -1
View File
@@ -1,6 +1,6 @@
from typing import Dict, Any
from src.models import ContextPreset
from src.project_files import ContextPreset
from src.result_types import Result, ErrorInfo, ErrorKind
+1 -1
View File
@@ -28,7 +28,7 @@ See Also:
"""
from typing import List
from src.models import Ticket
from src.mma import Ticket
from src.performance_monitor import get_monitor
+3 -3
View File
@@ -9,7 +9,7 @@ import tempfile
from pathlib import Path
from typing import Optional, List, Dict, Any
from src.models import ExternalEditorConfig, TextEditorConfig
from src.external_editor import ExternalEditorConfig, TextEditorConfig
from src.result_types import ErrorInfo, ErrorKind, Result
@@ -24,7 +24,7 @@ class ExternalEditorLauncher:
"""
[C: tests/test_external_editor.py:TestExternalEditorLauncher.test_get_editor_by_name, tests/test_external_editor.py:TestExternalEditorLauncher.test_get_editor_returns_default, tests/test_external_editor.py:TestExternalEditorLauncher.test_get_editor_unknown_name]
"""
from src.models import EMPTY_TEXT_EDITOR_CONFIG
from src.external_editor import EMPTY_TEXT_EDITOR_CONFIG
if editor_name:
return self.config.editors.get(editor_name) or EMPTY_TEXT_EDITOR_CONFIG
return self.config.get_default()
@@ -96,7 +96,7 @@ def _find_vscode_common_paths() -> str:
def auto_detect_vscode() -> TextEditorConfig:
from src.models import EMPTY_TEXT_EDITOR_CONFIG
from src.external_editor import EMPTY_TEXT_EDITOR_CONFIG
global _cached_vscode_config
if _cached_vscode_config is not None:
return _cached_vscode_config
+1 -1
View File
@@ -44,7 +44,7 @@ from src import paths
from src import summarize
from src.dag_engine import TrackDAG, ExecutionEngine
from src.models import Ticket, Track, WorkerContext
from src.mma import Ticket, Track, WorkerContext
from src.personas import PersonaManager
from src.result_types import ErrorInfo, ErrorKind, Result
+1 -1
View File
@@ -8,7 +8,7 @@ from src import ai_client
from src import mma_prompts
from src import paths
from src import summarize
from src.models import FileItem
from src.project_files import FileItem
from src.result_types import Result, ErrorInfo, ErrorKind
from src.type_aliases import Metadata
+1 -1
View File
@@ -4,7 +4,7 @@ import tomli_w
from pathlib import Path
from typing import Dict, Any, Optional
from src.models import Persona
from src.personas import Persona
from src import paths
class PersonaManager:
+1 -1
View File
@@ -5,7 +5,7 @@ import tomli_w
from pathlib import Path
from typing import Dict, Any, Optional
from src.models import Preset
from src.project_files import Preset
from src.paths import get_global_presets_path, get_project_presets_path
from src.result_types import ErrorInfo, ErrorKind, Result
+3 -3
View File
@@ -32,7 +32,7 @@ from src.type_aliases import (
)
if TYPE_CHECKING:
from src.models import TrackState
from src.mma import TrackState
TS_FMT: str = "%Y-%m-%dT%H:%M:%S"
@@ -270,7 +270,7 @@ def flat_config(proj: Metadata, disc_name: Optional[str] = None, track_id: Optio
The returned dataclass supports dict-compat (__getitem__ / get) so
existing consumers using .get() and [] continue to work unchanged
(Phase 2 Option A per SPEC_CORRECTION_phase_2.md)."""
from src.models import ProjectContext, ProjectMeta, ProjectOutput, ProjectFiles, ProjectScreenshots, ProjectDiscussion
from src.project import ProjectContext, ProjectMeta, ProjectOutput, ProjectFiles, ProjectScreenshots, ProjectDiscussion
disc_sec = proj.get("discussion", {})
if track_id:
history = load_track_history(track_id, proj.get("files", {}).get("base_dir", "."))
@@ -321,7 +321,7 @@ def load_track_state(track_id: str, base_dir: Union[str, Path] = ".") -> "TrackS
Returns empty TrackState (zero-init) if not found.
[C: tests/test_track_state_persistence.py:test_track_state_persistence]
"""
from src.models import TrackState, EMPTY_TRACK_STATE
from src.mma import TrackState, EMPTY_TRACK_STATE
state_file = paths.get_track_state_dir(track_id, project_path=str(base_dir)) / 'state.toml'
if not state_file.exists(): return EMPTY_TRACK_STATE
try:
+1 -1
View File
@@ -2,7 +2,7 @@ import re
from typing import List, Tuple
from src.models import ThinkingSegment
from src.mma import ThinkingSegment
def parse_thinking_trace(text: str) -> Tuple[List[ThinkingSegment], str]:
+3 -1
View File
@@ -1,6 +1,8 @@
from typing import List, Dict, Any, Optional
from src.models import Tool, ToolPreset, BiasProfile
from src.tool_bias import BiasProfile
from src.tool_presets import Tool, ToolPreset
class ToolBiasEngine:
+2 -1
View File
@@ -5,7 +5,8 @@ from pathlib import Path
from typing import Dict, List, Optional, Union, Any
from src import paths
from src.models import ToolPreset, BiasProfile
from src.tool_bias import BiasProfile
from src.tool_presets import ToolPreset
class ToolPresetManager:
+1 -1
View File
@@ -4,7 +4,7 @@ import tomli_w
from pathlib import Path
from typing import Dict, Any, Optional, Union
from src.models import WorkspaceProfile
from src.workspace_manager import WorkspaceProfile
from src import paths
+5 -5
View File
@@ -7,7 +7,7 @@ class TestArchBoundaryPhase3(unittest.TestCase):
pass
def test_cascade_blocks_simple(self) -> None:
"""Test that a blocked dependency blocks its immediate dependent."""
from src.models import Ticket, Track
from src.mma import Ticket, Track
t1 = Ticket(id="T1", description="d1", status="blocked", assigned_to="worker1")
t2 = Ticket(id="T2", description="d2", status="todo", assigned_to="worker1", depends_on=["T1"])
track = Track(id="TR1", description="track", tickets=[t1, t2])
@@ -20,7 +20,7 @@ class TestArchBoundaryPhase3(unittest.TestCase):
self.assertIn("T1", t2.blocked_reason)
def test_cascade_blocks_multi_hop(self) -> None:
"""Test that blocking cascades through multiple dependencies."""
from src.models import Ticket
from src.mma import Ticket
from src.dag_engine import TrackDAG, ExecutionEngine
t1 = Ticket(id="T1", description="d1", status="blocked", assigned_to="worker1")
t2 = Ticket(id="T2", description="d2", status="todo", assigned_to="worker1", depends_on=["T1"])
@@ -32,7 +32,7 @@ class TestArchBoundaryPhase3(unittest.TestCase):
self.assertEqual(t3.status, "blocked")
def test_manual_unblock_restores_todo(self) -> None:
"""Test that unblocking a task manually works if dependencies are met."""
from src.models import Ticket
from src.mma import Ticket
from src.dag_engine import TrackDAG, ExecutionEngine
t1 = Ticket(id="T1", description="d1", status="completed", assigned_to="worker1")
t2 = Ticket(id="T2", description="d2", status="blocked", assigned_to="worker1", blocked_reason="manual")
@@ -44,7 +44,7 @@ class TestArchBoundaryPhase3(unittest.TestCase):
self.assertIn(t2, ready)
def test_in_progress_not_blocked(self) -> None:
"""Test that in_progress tasks are not blocked automatically (only todo)."""
from src.models import Ticket
from src.mma import Ticket
from src.dag_engine import TrackDAG, ExecutionEngine
t1 = Ticket(id="T1", description="d1", status="blocked", assigned_to="worker1")
t2 = Ticket(id="T2", description="d2", status="in_progress", assigned_to="worker1", depends_on=["T1"])
@@ -54,7 +54,7 @@ class TestArchBoundaryPhase3(unittest.TestCase):
self.assertEqual(t2.status, "in_progress")
def test_execution_engine_tick_cascades_blocks(self) -> None:
"""Test that ExecutionEngine.tick() triggers the cascading blocks."""
from src.models import Ticket
from src.mma import Ticket
from src.dag_engine import TrackDAG, ExecutionEngine
t1 = Ticket(id="T1", description="d1", status="blocked", assigned_to="worker1")
t2 = Ticket(id="T2", description="d2", status="todo", assigned_to="worker1", depends_on=["T1"])
+2 -1
View File
@@ -1,6 +1,7 @@
import pytest
from src import ai_client
from src.models import ToolPreset, Tool, BiasProfile
from src.tool_bias import BiasProfile
from src.tool_presets import ToolPreset, Tool
from unittest.mock import MagicMock, patch
def test_bias_efficacy_prompt_generation():
+2 -1
View File
@@ -1,6 +1,7 @@
import pytest
from src import ai_client
from src.models import ToolPreset, Tool, BiasProfile
from src.tool_bias import BiasProfile
from src.tool_presets import ToolPreset, Tool
from unittest.mock import MagicMock, patch
def test_system_prompt_biasing():
+2 -1
View File
@@ -1,5 +1,6 @@
import pytest
from src.models import Tool, ToolPreset, BiasProfile
from src.tool_bias import BiasProfile
from src.tool_presets import Tool, ToolPreset
def test_tool_model():
tool = Tool(name="read_file", weight=5, parameter_bias={"path": "preferred"})
+1 -1
View File
@@ -1,7 +1,7 @@
import pytest
from unittest.mock import MagicMock, patch
from src.multi_agent_conductor import ConductorEngine
from src.models import Ticket, Track
from src.mma import Ticket, Track
import threading
def test_conductor_abort_event_populated():
+1 -1
View File
@@ -3,7 +3,7 @@ from unittest.mock import MagicMock
import threading
import time
from src.multi_agent_conductor import ConductorEngine
from src.models import Track
from src.mma import Track
def test_conductor_engine_initializes_empty_worker_and_abort_dicts() -> None:
"""
+1 -1
View File
@@ -4,7 +4,7 @@ They MUST NOT be simplified, and their assertions on exact call counts and depen
"""
import pytest
from unittest.mock import MagicMock, patch
from src.models import Ticket, Track, WorkerContext
from src.mma import Ticket, Track, WorkerContext
from src import ai_client
from src.result_types import Result
+1 -1
View File
@@ -1,7 +1,7 @@
import unittest
from unittest.mock import patch
from src import conductor_tech_lead
from src.models import Ticket
from src.mma import Ticket
from src.result_types import Result
import pytest
+1 -1
View File
@@ -1,7 +1,7 @@
import pytest
from pathlib import Path
from src.app_controller import AppController
from src.models import FileItem
from src.project_files import FileItem
def test_context_files_is_decoupled():
controller = AppController()
+1 -1
View File
@@ -1,6 +1,6 @@
import pytest
from src.aggregate import group_files_by_dir, compute_file_stats
from src.models import FileItem
from src.project_files import FileItem
def test_group_files_by_dir():
files = [
+1 -1
View File
@@ -1,6 +1,6 @@
import pytest
from src.gui_2 import App
from src.models import FileItem
from src.project_files import FileItem
def test_view_mode_initialization():
app = App()
+1 -1
View File
@@ -1,6 +1,6 @@
import pytest
from src.context_presets import ContextPresetManager
from src.models import ContextPreset, ContextFileEntry
from src.project_files import ContextPreset, ContextFileEntry
def test_save_context_preset():
manager = ContextPresetManager()
+1 -1
View File
@@ -1,6 +1,6 @@
import pytest
from src.context_presets import ContextPresetManager
from src.models import ContextPreset, ContextFileEntry
from src.project_files import ContextPreset, ContextFileEntry
from src.app_controller import AppController
from pathlib import Path
import tomli_w
+1 -1
View File
@@ -1,5 +1,5 @@
import pytest
from src.models import ContextPreset, ContextFileEntry
from src.project_files import ContextPreset, ContextFileEntry
def test_context_file_entry_serialization():
p = ContextFileEntry(path="test.py", view_mode="skeleton")
+2 -2
View File
@@ -2,7 +2,7 @@ import pytest
from unittest.mock import Mock
from pathlib import Path
from src.gui_2 import App
from src.models import FileItem
from src.project_files import FileItem
def test_preview_button_syncs_context_files_to_controller():
app = Mock(spec=App)
@@ -51,7 +51,7 @@ def test_preview_generates_nonempty_for_real_files(monkeypatch):
"""Integration test: Preview button should generate content when context_files has real FileItems."""
import src.project_manager as pm
import src.aggregate as agg
from src.models import FileItem
from src.project_files import FileItem
app = Mock(spec=App)
test_file = FileItem(path='tests/test_context_composition_decoupled.py', view_mode='summary')
+1 -1
View File
@@ -2,7 +2,7 @@ import pytest
import time
from pathlib import Path
from src.file_cache import ASTParser
from src.models import Ticket, Track, WorkerContext
from src.mma import Ticket, Track, WorkerContext
from src.multi_agent_conductor import run_worker_lifecycle
from src.result_types import Result
+1 -1
View File
@@ -1,5 +1,5 @@
import pytest
from src.models import FileItem
from src.project_files import FileItem
def test_file_item_custom_slices_serialization_with_annotations():
# Test that FileItem correctly serializes custom_slices with tag and comment.
+1 -1
View File
@@ -4,7 +4,7 @@ They MUST NOT be simplified. They ensure that dependency resolution, cycle detec
and topological sorting work perfectly to prevent catastrophic orchestrator deadlocks.
"""
import pytest
from src.models import Ticket
from src.mma import Ticket
from src.dag_engine import TrackDAG
def test_get_ready_tasks_linear():
+1 -1
View File
@@ -1,4 +1,4 @@
from src.models import Ticket
from src.mma import Ticket
from src.dag_engine import TrackDAG, ExecutionEngine
def test_execution_engine_basic_flow():
+1 -1
View File
@@ -1,7 +1,7 @@
"""Tests for external editor integration."""
import pytest
from unittest.mock import patch, MagicMock
from src.models import TextEditorConfig, ExternalEditorConfig
from src.external_editor import TextEditorConfig, ExternalEditorConfig
from src.external_editor import (
ExternalEditorLauncher,
get_default_launcher,
+1 -1
View File
@@ -1,5 +1,5 @@
import pytest
from src.models import FileItem
from src.project_files import FileItem
def test_file_item_fields():
"""Test that FileItem exists and has correct default values."""
+2 -2
View File
@@ -2315,7 +2315,7 @@ def test_phase_10_l7271_dag_cycle_check_result_no_cycle():
opening the "Cycle Detected!" popup.
"""
from unittest.mock import MagicMock, patch
from src.models import Ticket
from src.mma import Ticket
import src.gui_2 as gui2_mod
app = MagicMock()
app.active_tickets = [Ticket(id="T-001", description="T-001", depends_on=[])]
@@ -2335,7 +2335,7 @@ def test_phase_10_l7271_dag_cycle_check_result_cycle_detected():
returns Result(data=True). The caller opens the "Cycle Detected!" popup.
"""
from unittest.mock import MagicMock, patch
from src.models import Ticket
from src.mma import Ticket
import src.gui_2 as gui2_mod
app = MagicMock()
app.active_tickets = [
+1 -1
View File
@@ -2,7 +2,7 @@ import pytest
from unittest.mock import MagicMock, patch
from src import gui_2
from src.gui_2 import App
from src.models import Track
from src.mma import Track
@pytest.fixture(autouse=True)
def setup_mock_app(mock_app: App):
+1 -1
View File
@@ -2,7 +2,7 @@ import pytest
from unittest.mock import MagicMock, patch
from src import gui_2
from src.gui_2 import App, C_LBL, C_VAL
from src.models import Ticket
from src.mma import Ticket
def test_render_mma_dashboard_progress():
# Create a mock for the imgui module used in gui_2
+1 -1
View File
@@ -1,7 +1,7 @@
from typing import Any
import pytest
from unittest.mock import MagicMock, patch
from src.models import Ticket, Track
from src.mma import Ticket, Track
from src import multi_agent_conductor
from src.multi_agent_conductor import ConductorEngine
from src import ai_client
+1 -1
View File
@@ -1,5 +1,5 @@
import pytest
from src.models import Ticket
from src.mma import Ticket
def test_ticket_has_manual_block_field():
t = Ticket(id="T-001", description="Test")
+2 -2
View File
@@ -10,7 +10,7 @@ Verifies:
import inspect
from unittest.mock import patch
from src.models import Ticket
from src.mma import Ticket
class TestActiveTicketsType:
@@ -58,7 +58,7 @@ class TestActiveTicketsLoadBoundaries:
def test_load_active_tickets_beads_branch_converts_dicts_to_tickets(self) -> None:
"""_load_active_tickets (beads branch) must wrap bead dicts as models.Ticket."""
from src.app_controller import AppController
from src.models import Ticket
from src.mma import Ticket
ctrl = AppController.__new__(AppController)
ctrl._last_request_errors = []
ctrl.ui_project_execution_mode = "beads"
+1 -1
View File
@@ -1,4 +1,4 @@
from src.models import Ticket, Track, WorkerContext
from src.mma import Ticket, Track, WorkerContext
from src.dag_engine import get_executable_tickets
def test_ticket_instantiation() -> None:
+1 -1
View File
@@ -1,5 +1,5 @@
from src.gui_2 import App
from src.models import Ticket
from src.mma import Ticket
def test_cb_ticket_retry(app_instance: App) -> None:
ticket_id = "test_ticket_1"
+1 -1
View File
@@ -3,7 +3,7 @@ from unittest.mock import patch, MagicMock
from src import orchestrator_pm
from src import multi_agent_conductor
from src import conductor_tech_lead
from src.models import Ticket, Track, WorkerContext
from src.mma import Ticket, Track, WorkerContext
from src.result_types import Result
def test_generate_tracks() -> None:
+1 -1
View File
@@ -67,7 +67,7 @@ def test_worker_pool_completion_cleanup():
assert "t1" not in pool._active
from unittest.mock import patch
from src.models import Track, Ticket
from src.mma import Track, Ticket
from src.multi_agent_conductor import ConductorEngine
@patch('src.multi_agent_conductor.run_worker_lifecycle')
+1 -1
View File
@@ -1,5 +1,5 @@
import pytest
from src.models import Ticket
from src.mma import Ticket
def test_ticket_has_model_override_field():
t = Ticket(id="T-001", description="Test")
+1 -1
View File
@@ -1,5 +1,5 @@
import pytest
from src.models import Ticket
from src.mma import Ticket
from src.dag_engine import TrackDAG
from src.performance_monitor import get_monitor
+1 -1
View File
@@ -1,5 +1,5 @@
import pytest
from src.models import Ticket, WorkerContext
from src.mma import Ticket, WorkerContext
def test_ticket_persona_id_serialization():
+1 -1
View File
@@ -1,7 +1,7 @@
import pytest
import tomli_w
from pathlib import Path
from src.models import Persona
from src.personas import Persona
from src.personas import PersonaManager
from src import paths
+1 -1
View File
@@ -1,5 +1,5 @@
import pytest
from src.models import Persona
from src.personas import Persona
def test_persona_serialization():
persona = Persona(
+1 -1
View File
@@ -1,6 +1,6 @@
from unittest.mock import MagicMock, patch
from src.multi_agent_conductor import ConductorEngine, run_worker_lifecycle
from src.models import Ticket, Track, WorkerContext
from src.mma import Ticket, Track, WorkerContext
from src import ai_client
from src.result_types import Result
+1 -1
View File
@@ -1,6 +1,6 @@
import pytest
from unittest.mock import MagicMock, patch
from src.models import Ticket, Track
from src.mma import Ticket, Track
from src.multi_agent_conductor import ConductorEngine
def test_conductor_engine_has_pause_event():
+1 -1
View File
@@ -1,7 +1,7 @@
import pytest
from pathlib import Path
from src.presets import PresetManager
from src.models import Preset
from src.project_files import Preset
def test_load_all_merged(tmp_path, monkeypatch):
"""Tests that load_all correctly merges global and project presets."""
+1 -1
View File
@@ -4,7 +4,7 @@ from pathlib import Path
import tempfile
import shutil
from src.presets import PresetManager
from src.models import Preset
from src.project_files import Preset
class TestPresetManager(unittest.TestCase):
def setUp(self):
+1 -1
View File
@@ -1,6 +1,6 @@
import pytest
from src.project_manager import calculate_track_progress
from src.models import Ticket
from src.mma import Ticket
def test_calculate_track_progress_empty():
results = calculate_track_progress([])
+2 -1
View File
@@ -2,7 +2,8 @@ import pytest
from typing import Any
import json
from src.project_manager import get_all_tracks, save_track_state
from src.models import TrackState, Metadata, Ticket
from src.mma import TrackState, Ticket
from src.models import Metadata
from datetime import datetime
def test_get_all_tracks_empty(tmp_path: Any) -> None:
+1 -1
View File
@@ -5,7 +5,7 @@ import tempfile
import pytest
from src.rag_engine import RAGEngine
from src.models import RAGConfig, VectorStoreConfig
from src.mcp_client import RAGConfig, VectorStoreConfig
LOCAL_EMBED_DIM = 384
+1 -1
View File
@@ -4,7 +4,7 @@ import threading
import json
import time
from src.multi_agent_conductor import run_worker_lifecycle
from src.models import Ticket, WorkerContext
from src.mma import Ticket, WorkerContext
class TestRunWorkerLifecycleAbort(unittest.TestCase):
def test_run_worker_lifecycle_returns_early_on_abort(self):
+1 -1
View File
@@ -1,5 +1,5 @@
import pytest
from src.models import FileItem
from src.project_files import FileItem
from src.fuzzy_anchor import FuzzyAnchor
def test_add_slice_with_annotations():
+1 -1
View File
@@ -1,7 +1,7 @@
import pytest
from unittest.mock import MagicMock, patch
from src import multi_agent_conductor
from src.models import Ticket, WorkerContext
from src.mma import Ticket, WorkerContext
from src import events
from src.result_types import Result
import threading
+1 -1
View File
@@ -32,7 +32,7 @@ def test_discussion_entry_without_thinking():
def test_thinking_segment_model_compatibility():
from src.models import ThinkingSegment
from src.mma import ThinkingSegment
segment = ThinkingSegment(content="test", marker="thinking")
assert segment.content == "test"
+1 -1
View File
@@ -3,7 +3,7 @@ import tempfile
import os
from pathlib import Path
from src import project_manager
from src.models import ThinkingSegment
from src.mma import ThinkingSegment
def test_save_and_load_history_with_thinking_segments():
+1 -1
View File
@@ -1,6 +1,6 @@
import pytest
from unittest.mock import patch
from src.models import Ticket
from src.mma import Ticket
def test_ticket_priority_default():
ticket = Ticket(id="T1", description="Test ticket")
+2 -1
View File
@@ -1,5 +1,6 @@
import pytest
from src.models import Persona, Ticket, WorkerContext
from src.mma import Ticket, WorkerContext
from src.personas import Persona
from src import multi_agent_conductor
from src import app_controller
from src import aggregate
+2 -1
View File
@@ -1,6 +1,7 @@
import pytest
from src.tool_bias import ToolBiasEngine
from src.models import ToolPreset, Tool, BiasProfile
from src.tool_bias import BiasProfile
from src.tool_presets import ToolPreset, Tool
def test_apply_semantic_nudges():
engine = ToolBiasEngine()
+2 -1
View File
@@ -2,7 +2,8 @@ import pytest
import tomli_w
from pathlib import Path
from src.tool_presets import ToolPresetManager
from src.models import ToolPreset, BiasProfile, Tool
from src.tool_bias import BiasProfile
from src.tool_presets import ToolPreset, Tool
from src import paths
@pytest.fixture
+1 -1
View File
@@ -3,7 +3,7 @@ import asyncio
from src import ai_client
from src import mcp_client
from src import models
from src.models import ToolPreset, Tool
from src.tool_presets import ToolPreset, Tool
from unittest.mock import MagicMock, patch
@pytest.mark.asyncio
+2 -1
View File
@@ -1,7 +1,8 @@
from datetime import datetime
# Import the real models
from src.models import TrackState, Metadata, Ticket
from src.mma import TrackState, Ticket
from src.models import Metadata
# Import the persistence functions from project_manager
from src.project_manager import save_track_state, load_track_state
+2 -1
View File
@@ -1,7 +1,8 @@
from datetime import datetime, timezone, timedelta
# Import necessary classes from models.py
from src.models import Metadata, TrackState, Ticket
from src.mma import TrackState, Ticket
from src.models import Metadata
# --- Pytest Tests ---
+1 -1
View File
@@ -1,7 +1,7 @@
import pytest
from pathlib import Path
from src.workspace_manager import WorkspaceManager
from src.models import WorkspaceProfile
from src.workspace_manager import WorkspaceProfile
from src import paths
def test_load_all_profiles_merged(tmp_path, monkeypatch):
@@ -2,7 +2,7 @@ import io
import tomllib
import pytest
import tomli_w
from src.models import WorkspaceProfile
from src.workspace_manager import WorkspaceProfile
def test_workspace_profile_empty_ini_content_roundtrips():