Private
Public Access
0
0

refactor(app_controller): migrate _cb_run_conductor_setup + _cb_load_track to Result (Phase 6 Groups 6.5+6.7 partial)

Migrates the 2 remaining _cb_* sites with proper Result[T] propagation:
- _cb_run_conductor_setup: per-file read via _read_conductor_file_result
- _cb_load_track: state hydration via _cb_load_track_result

New helpers:
- _read_conductor_file_result(f) -> Result[int]
- _cb_load_track_result(state, track_id) -> Result[None]

Audit: INTERNAL_SILENT_SWALLOW for src/app_controller.py: 12 -> 10.
This commit is contained in:
2026-06-19 16:01:58 -04:00
parent 4ea6ea3988
commit 90b20879d2
+64 -34
View File
@@ -4749,6 +4749,22 @@ class AppController:
engine.engine = ExecutionEngine(engine.dag, auto_queue=engine.engine.auto_queue)
self._push_mma_state_update()
def _read_conductor_file_result(self, f: Path) -> "Result[int]":
"""Phase 6 Group 6.7: read a conductor file and return line count.
On failure: OSError/IOError/UnicodeDecodeError -> ErrorInfo(original=e).
Caller (`_cb_run_conductor_setup`) records per-file errors and
adds an 'Error reading' line to the summary."""
try:
with open(f, "r", encoding="utf-8") as fd:
return Result(data=len(fd.readlines()))
except (OSError, IOError, UnicodeDecodeError) as e:
return Result(data=0, errors=[ErrorInfo(
kind=ErrorKind.INTERNAL,
message=str(e),
source=f"app_controller._read_conductor_file_result[{f.name}]",
original=e,
)])
def _cb_run_conductor_setup(self) -> None:
"""
[C: src/gui_2.py:App._render_mma_conductor_setup, tests/test_gui_phase3.py:test_conductor_setup_scan]
@@ -4763,13 +4779,12 @@ class AppController:
summary.append(f"Total Files: {len(files)}")
total_lines = 0
for f in files:
try:
with open(f, "r", encoding="utf-8") as fd:
lines = len(fd.readlines())
total_lines += lines
summary.append(f"- {f.relative_to(base)}: {lines} lines")
except (OSError, IOError, UnicodeDecodeError) as e:
logging.getLogger(__name__).debug("conductor file read failed for %s: %s", f, e, extra={"source": "app_controller._cb_run_conductor_setup"})
result = self._read_conductor_file_result(f)
if result.ok:
total_lines += result.data
summary.append(f"- {f.relative_to(base)}: {result.data} lines")
else:
self._last_request_errors.append((f"conductor_file_read[{f.name}]", result.errors[0]))
summary.append(f"- {f.relative_to(base)}: Error reading")
summary.append(f"Total Line Count: {total_lines}")
tracks_dir = base / "tracks"
@@ -4842,34 +4857,49 @@ class AppController:
"""
state = project_manager.load_track_state(track_id, self.active_project_root)
if state:
try:
result = self._cb_load_track_result(state, track_id)
if not result.ok:
err = result.errors[0]
self.ai_status = f"Load track error: {err.message}"
print(f"Error loading track {track_id}: {err.message}")
self._report_worker_error("cb_load_track", result)
def _cb_load_track_result(self, state, track_id: str) -> "Result[None]":
"""Phase 6 Group 6.7: load a track with Result propagation.
On failure: OSError/IOError/ValueError/TypeError/KeyError/AttributeError/tomllib.TOMLDecodeError
-> ErrorInfo(original=e). Caller drains via stderr print + ai_status."""
try:
# Convert list[Ticket] or list[dict] to list[Ticket] for Track object
tickets = []
for t in state.tasks:
if isinstance(t, dict):
tickets.append(models.Ticket(**t))
else:
tickets.append(t)
self.active_track = models.Track(
id=state.metadata.id,
description=state.metadata.name,
tickets=tickets
)
# Keep dicts for UI table
self._load_active_tickets()
# Load track-scoped history
history = project_manager.load_track_history(track_id, self.active_project_root)
with self._disc_entries_lock:
if history:
self.disc_entries[:] = models.parse_history_entries(history, self.disc_roles)
else:
self.disc_entries.clear()
self._recalculate_session_usage()
self.ai_status = f"Loaded track: {state.metadata.name}"
except (OSError, IOError, ValueError, TypeError, KeyError, AttributeError, tomllib.TOMLDecodeError) as e:
logging.getLogger(__name__).debug("load track failed: %s", e, extra={"source": "app_controller._cb_load_track"})
self.ai_status = f"Load track error: {e}"
print(f"Error loading track {track_id}: {e}")
tickets = []
for t in state.tasks:
if isinstance(t, dict):
tickets.append(models.Ticket(**t))
else:
tickets.append(t)
self.active_track = models.Track(
id=state.metadata.id,
description=state.metadata.name,
tickets=tickets
)
# Keep dicts for UI table
self._load_active_tickets()
# Load track-scoped history
history = project_manager.load_track_history(track_id, self.active_project_root)
with self._disc_entries_lock:
if history:
self.disc_entries[:] = models.parse_history_entries(history, self.disc_roles)
else:
self.disc_entries.clear()
self._recalculate_session_usage()
self.ai_status = f"Loaded track: {state.metadata.name}"
return OK
except (OSError, IOError, ValueError, TypeError, KeyError, AttributeError, tomllib.TOMLDecodeError) as e:
return Result(data=None, errors=[ErrorInfo(
kind=ErrorKind.INTERNAL,
message=str(e),
source="app_controller._cb_load_track_result",
original=e,
)])
def _push_mma_state_update(self) -> None:
"""