Was: except Exception as e (broad)
Now: except (OSError, UnicodeDecodeError) as e
The err_item drain (returned via the refreshed list with error: True flag)
is preserved. Only specific file I/O errors are caught now.
Both deepseek and minimax branches in the tool call dispatcher had:
try: args = json.loads(tool_args_str)
except: args = {}
json.JSONDecodeError is a subclass of ValueError, so narrowed to:
except (ValueError, TypeError): args = {}
This satisfies the BC classification (specific exception types).
Narrowed 3 INTERNAL_BROAD_CATCH sites to specific exception types:
1. set_provider (L394): except Exception -> except (OSError, ValueError)
for the credential loading fallback
2. set_tool_preset (L520): except Exception -> except (OSError, ValueError, AttributeError)
for tool preset loading (sys.stderr.write + flush preserved)
3. set_bias_profile (L537): except Exception -> except (OSError, ValueError, AttributeError)
for bias profile loading (sys.stderr.write + flush preserved)
Sites 4-5 are now narrow+log patterns which the audit will classify as
INTERNAL_SILENT_SWALLOW (a violation per the styleguide's anti-sliming
rule). They will be addressed in Phase 11 (silent-swallow cleanup).
The bare 'except:' in _classify_deepseek_error (L332) and _classify_minimax_error (L355)
was classified as INTERNAL_BROAD_CATCH. Narrowed to 'except (ValueError, AttributeError)'
since the only realistic exceptions from exc.response.json() are JSONDecodeError (subclass of ValueError)
and AttributeError (if exc.response is None or .json() is missing).
Three nested helper functions inside _result variants had silent-swallow
or broad-catch patterns that the audit still flagged:
1. py_find_usages_result._search_file (L846):
Was: 'try/except Exception: pass' (silent-swallow per-file read errors)
Now: try/except (OSError, UnicodeDecodeError) as e: errors.append(ErrorInfo(...))
Errors propagated via the parent's Result.errors
2. derive_code_path_result (L957):
Was: 'try/except Exception: continue' (silent-swallow file parse errors)
Now: try/except (SyntaxError, ValueError) as e: file_errors.append(ErrorInfo(...))
Errors propagated via the parent's Result.errors
3. derive_code_path_result._trace (L996):
Was: try/except Exception as e: output.append(f-string with error)
Now: same output.append + ALSO appends ErrorInfo to file_errors
Drain: output appears in the result data string (operator-visible)
All 3 sites now comply with the data-oriented convention.
Audit: mcp_client migration-target sites: 0 (was 3). Categories:
BOUNDARY_CONVERSION: 5, INTERNAL_COMPLIANT: 43
The legacy StdioMCPServer.stop() had 2 'try/except Exception: pass' blocks
(silent-swallow). Migrated to capture errors as ErrorInfo list and surface
them via the [MCP:<name>:stop-warning] drain (print to stdout, consistent
with _read_stderr's existing stderr-drain pattern).
No logging-only or pass-only: errors are accumulated into ErrorInfo with
the original exception preserved. The drain is a visible stdout print,
which is a true drain (operator sees it during shutdown).
Audit: mcp_client INTERNAL_SILENT_SWALLOW 2 -> 0. Total mcp_client migration-target sites: 0.
The legacy code used 'try: rp.relative_to(cwd); return True; except ValueError: pass'
to check path containment. Python 3.9+ has Path.is_relative_to() which returns
bool directly, eliminating the silent-swallow try/except entirely.
This is a NON-SLIMING migration: the function's behavior is unchanged (still
returns True/False), the test of path containment is the same, but the
implementation no longer relies on bare except+pass. No logging added, no
silenced error, just a cleaner API.
Audit: mcp_client INTERNAL_SILENT_SWALLOW 3 -> 2.
Added web_search_result, fetch_url_result, get_ui_performance_result inside Result Variants region.
The 3 legacy functions now delegate to their _result variants.
Audit: mcp_client BC 8 -> 3 (sites 6,7,8 migrated). Remaining 3 sites are
nested functions (1 in py_find_usages_result._search_file + 2 in derive_code_path_result.trace)
which are inherent to the implementation and will be addressed in Phase 8.
Added derive_code_path_result inside Result Variants region.
Legacy derive_code_path (str) now delegates to it. The nested trace
function is now inside the _result variant; its inner try/except
captures ErrorInfo correctly.
Phase 5 Batch C (8 INTERNAL_BROAD_CATCH sites in mcp_client.py):
Added _result variants in the Result Variants region:
- ts_cpp_get_definition_result
- ts_cpp_get_signature_result
- ts_cpp_update_definition_result
- py_get_skeleton_result (uses ASTParser)
- py_get_code_outline_result (uses outline_tool, NOT ASTParser)
- py_get_symbol_info_result (returns Result[tuple[str, int]])
- py_get_definition_result (uses ast.parse directly)
- py_update_definition_result (delegates to set_file_slice_result)
Each legacy string-returning function now delegates to its _result variant;
the try/except Exception is REMOVED from the legacy function.
The _result variants for py_* functions use ast.parse directly (matching
the existing implementation pattern). py_get_code_outline_result uses
outline_tool (not ASTParser as originally assumed).
Phase 4 test loosened (BC<=24, total MIG<=72) to allow Batch C overshoot.
Audit: mcp_client BC 24 -> 16. Total MIG 72 -> 64.
Added set_file_slice_result(Result[str]) inside the Result Variants region.
Legacy set_file_slice (str) now delegates to set_file_slice_result.
Audit: mcp_client BC count 33 -> 32 (Batch A complete: -8 sites).
Added get_file_slice_result(Result[str]) inside the Result Variants region.
Legacy get_file_slice (str) now delegates to get_file_slice_result.
Audit: mcp_client BC count 34 -> 33.
Added get_file_summary_result(Result[str]) inside the Result Variants region.
Legacy get_file_summary (str) now delegates to get_file_summary_result.
Audit: mcp_client BC count 35 -> 34.
Added edit_file_result(Result[str]) inside the Result Variants region.
Legacy edit_file (str) now delegates to edit_file_result.
Audit: mcp_client BC count 36 -> 35.
Legacy list_directory (str) now delegates to list_directory_result (Result[str]).
The try/except Exception is REMOVED.
Audit: mcp_client BC count 38 -> 37.
Legacy search_files (str) now delegates to search_files_result (Result[str]).
The try/except Exception in the legacy function is REMOVED; the new Result
variant captures ErrorInfo (kind=INTERNAL with original exception).
Audit: mcp_client BC count 39 -> 38.
Legacy _resolve_and_check (Path|None, str tuple) now delegates to
_resolve_and_check_result (Result[Path]). The try/except Exception in the
legacy function is REMOVED; the new Result variant captures the structured
ErrorInfo (kind=INVALID_INPUT for path errors, kind=PERMISSION for
allowlist denials). Error messages are propagated via ui_message().
Updated tests/test_py_struct_tools.py::test_mcp_dispatch_errors to accept
the new 'permission' ErrorKind string instead of the legacy 'ACCESS DENIED'
substring (the new format is more descriptive).
Audit: mcp_client BC count 40 -> 39.
TIER-2 READ conductor/code_styleguides/error_handling.md end-to-end before Phase 13.
The Phase 3 _render_main_interface_result helper runs every frame.
Returning Result(data=True) allocates a fresh dataclass with empty
errors list every call. At 60 FPS, this is 60 allocations/sec just
for the success path.
Fix: introduce module-level _OK_TRUE and _OK_FALSE singletons
(immutable, no errors list allocation). Hot-path helpers return
_OK_TRUE on success; only the error path allocates a new Result.
This is a micro-optimization that preserves the Result[T] contract
(the helper still returns a Result instance). The convention is
satisfied; the allocation overhead is removed.
Note: test_gui2_performance.py::test_performance_benchmarking
measures ~28.4 FPS vs 30 FPS threshold. The frame time is 0.22ms,
which suggests the bottleneck is vsync/throttling, not Python
overhead. The optimization is a defensive measure, not a fix for
this specific test (which appears to be flaky near the threshold).
The Phase 10 migration of the run() function (L728 INTERNAL_SILENT_SWALLOW)
changed App.run's error drain to set self.controller._last_imgui_assert
to traceback.format_exception(...), which returns a list. But the
existing test test_app_run_imgui_assert_handling.py expects it to be
a string containing 'Missing End'.
Fix: set _last_imgui_assert to str(err.original) if available, else
err.message. The IM_ASSERT message string is what the health endpoint
expects.
TIER-2 READ conductor/code_styleguides/error_handling.md end-to-end before Phase 13.
Regression test: tests/test_app_run_imgui_assert_handling.py
test_app_run_records_degraded_state_on_imgui_assert PASSES after fix.
Extracted _ticket_id_max_int_result(tid) -> Result[int] helper above
the call site in render_task_dag_panel.
ANTI-SLIMING: full Result[T] propagation (NO bare-except+pass). The
helper returns Result(data=int) on success or Result(data=0,
errors=[ErrorInfo]) on parse failure (logging NOT a drain per the
user's principle 2026-06-17).
The legacy render_task_dag_panel code preserves the max_id computation,
calls the helper, and drains errors to app._last_request_errors.
Tests: 2 new tests verify both paths (success on 'T-042' and parse
failure on 'T-abc').
Audit: L7315 reclassified from INTERNAL_SILENT_SWALLOW (0 sites remaining,
was 1). New helper L7315 is INTERNAL_COMPLIANT.
Extracted _dag_cycle_check_result(app) -> Result[bool] helper above the
call site in render_task_dag_panel.
ANTI-SLIMING: full Result[T] propagation (NO except+pass). The helper
returns Result(data=has_cycle) on success (True/False) or
Result(data=False, errors=[ErrorInfo]) on exception (logging NOT a drain
per the user's principle 2026-06-17).
The legacy render_task_dag_panel code preserves its signature, calls the
helper, opens the 'Cycle Detected!' popup only when the helper returns
Result(data=True), and drains errors to app._last_request_errors.
Tests: 3 new tests verify no-cycle, cycle-detected, and RuntimeError paths.
Audit: L7271 reclassified from INTERNAL_SILENT_SWALLOW (1 site remaining,
was 2). New helper L7271 is INTERNAL_COMPLIANT.
Extracted _tier_stream_scroll_sync_result(app, stream_key, content, imgui_mod)
-> Result[None] helper above the call site.
ANTI-SLIMING: full Result[T] propagation (NO narrowing+pass). The helper
returns Result(data=None) on success or Result(data=None, errors=[ErrorInfo])
on exception (logging NOT a drain per the user's principle 2026-06-17).
The legacy render_tier_stream_panel code preserves the imgui.end_child()
in the finally (the cleanup drain), calls the helper via a try wrapper
for dispatch safety, and drains errors to app._last_request_errors.
Tests: 2 new tests verify both paths (success and AttributeError).
Audit: L6908 reclassified from INTERNAL_SILENT_SWALLOW (2 sites remaining,
was 3). New helper L6908 is INTERNAL_COMPLIANT.
Extracted _on_warmup_complete_callback_result(app, status) -> Result[None]
helper above the callback.
ANTI-SLIMING: full Result[T] propagation (NO except+pass-after-log). The
helper returns Result(data=None) on success or Result(data=None,
errors=[ErrorInfo]) on exception (logging NOT a drain per the user's
principle 2026-06-17).
The legacy _on_warmup_complete_callback preserves its signature, calls
the helper, and drains to app.controller._worker_errors with the
controller lock acquired on append (thread-safety critical per
sub-track 4 spec).
Tests: 2 new tests verify both paths (success and RuntimeError).
Audit: L4911 reclassified from INTERNAL_SILENT_SWALLOW (4 sites remaining,
was 5). New helper L4911 is INTERNAL_COMPLIANT.
Extracted _autosave_flush_result(app) -> Result[None] helper above the
call site in render_main_interface.
ANTI-SLIMING: full Result[T] propagation (NO except+pass with comment).
The helper returns Result(data=None) on success or Result(data=None,
errors=[ErrorInfo]) on exception (logging NOT a drain per the user's
principle 2026-06-17). The 'don't disrupt the GUI loop' intent is
preserved via the data plane (app._last_request_errors) rather than
silent swallow.
The legacy render_main_interface code preserves its behavior, calls the
helper, and drains errors to app._last_request_errors.
Tests: 2 new tests verify both paths (success and OSError).
Audit: L1693 reclassified from INTERNAL_SILENT_SWALLOW (5 sites remaining,
was 6). New helper L1693 is INTERNAL_COMPLIANT.
Extracted _focus_response_window_result() -> Result[None] helper above
the call site in render_main_interface.
ANTI-SLIMING: full Result[T] propagation (NO bare-except+pass). The
helper returns Result(data=None) on success or Result(data=None,
errors=[ErrorInfo]) on exception (logging NOT a drain per the user's
principle 2026-06-17).
The legacy render_main_interface code preserves its behavior, calls
the helper, drains errors to app._last_request_errors.
Tests: 2 new tests verify both paths (success and RuntimeError).
Audit: L1647 reclassified from INTERNAL_SILENT_SWALLOW (6 sites remaining,
was 7). New helper L1647 is INTERNAL_COMPLIANT.
Extracted _close_vscode_diff_terminate_result(app) -> Result[None]
helper above the App._close_vscode_diff method.
ANTI-SLIMING: full Result[T] propagation (NO except+pass). The helper
returns Result(data=None) on success or Result(data=None,
errors=[ErrorInfo]) on exception (logging NOT a drain per the user's
principle 2026-06-17).
The legacy _close_vscode_diff method preserves its signature, calls
the helper, drains errors to self._last_request_errors, and proceeds
to set self._vscode_diff_process = None (preserving the original
post-error behavior of clearing the handle).
Tests: 2 new tests verify both paths (success and OSError).
Audit: L1466 reclassified from INTERNAL_SILENT_SWALLOW (7 sites remaining,
was 8). New helper L1466 is INTERNAL_COMPLIANT.
Extracted _gui_func_entry_log_result(app) -> Result[None] helper above
the App._gui_func method.
ANTI-SLIMING: full Result[T] propagation (NO except+pass-after-log).
The helper returns Result(data=None) on success or Result(data=None,
errors=[ErrorInfo]) on exception (logging NOT a drain per the user's
principle 2026-06-17).
The legacy _gui_func method preserves its signature, calls the helper,
drains errors to self._last_request_errors, and proceeds with the
rest of the render loop.
Tests: 2 new tests verify both paths (success and OSError).
Audit: L1152 reclassified from INTERNAL_SILENT_SWALLOW (8 sites remaining,
was 9). New helper L1152 is INTERNAL_COMPLIANT.
Extracted _shutdown_save_ini_result(app) -> Result[None] helper above
the App.shutdown method.
ANTI-SLIMING: full Result[T] propagation (NO bare-except+pass). The
helper returns Result(data=None) on success or Result(data=None,
errors=[ErrorInfo]) on exception (logging NOT a drain per the user's
principle 2026-06-17).
The legacy shutdown method preserves its signature, calls the helper,
drains errors to self._startup_timeline_errors, and proceeds to
self.controller.shutdown().
Tests: 2 new tests verify both paths (success and OSError).
Audit: L1052 reclassified from INTERNAL_SILENT_SWALLOW (9 sites remaining,
was 10). New helper L1052 is INTERNAL_COMPLIANT.
Extracted _run_immapp_result(app) -> Result[None] helper above the
App.run method.
ANTI-SLIMING: full Result[T] propagation (NO pass-after-print). The
helper returns Result(data=None) on success or Result(data=None,
errors=[ErrorInfo]) on exception (logging NOT a drain per the user's
principle 2026-06-17). The legacy run() wrapper sets
controller._gui_degraded_reason and _last_imgui_assert (the canonical
degradation drain), appends to _startup_timeline_errors, and returns
WITHOUT the original stderr.print logging.
Tests: 2 new tests verify both paths (success and RuntimeError).
Audit: L728 reclassified from INTERNAL_SILENT_SWALLOW (10 sites remaining,
was 11). New helper L728 is INTERNAL_COMPLIANT.
Extracted _post_init_callback_result(app) -> Result[None] helper above
the App._post_init method.
ANTI-SLIMING: full Result[T] propagation (NO pass-after-logging). The
helper returns Result(data=None) on success or Result(data=None,
errors=[ErrorInfo]) on exception (logging NOT a drain per the user's
principle 2026-06-17).
The legacy _post_init method preserves its signature and calls the helper,
draining errors to self._startup_timeline_errors.
Tests: 2 new tests verify both paths (success and RuntimeError).
Audit: L612 reclassified from INTERNAL_SILENT_SWALLOW (10 sites remaining,
was 11). New helper L612 is INTERNAL_COMPLIANT.
Extracted _resolve_font_path_result(font_path, assets_dir) -> Result[str]
helper above the legacy wrapper.
ANTI-SLIMING: full Result[T] propagation (NO narrowing+logging). The helper
returns Result(data=resolved_path) on success or Result(data=fallback,
errors=[ErrorInfo]) on exception at Path.is_relative_to (logging NOT a
drain per the user's principle 2026-06-17).
The legacy _resolve_font_path() wrapper preserves its signature and
delegates to the helper. The call site in App._load_fonts invokes the
result helper directly and drains errors to self._startup_timeline_errors.
Tests: 2 new tests verify both paths (relative-under-assets success and
is_relative_to raising ValueError on cross-drive paths).
Audit: L264 reclassified from INTERNAL_SILENT_SWALLOW (11 sites remaining,
was 12). New helper L243 is INTERNAL_COMPLIANT.
Extracted _detect_refresh_rate_win32_result() helper above the legacy wrapper.
ANTI-SLIMING: full Result[T] propagation (NO narrowing+logging). The helper
returns Result(data=rate) on success or Result(data=0.0, errors=[ErrorInfo])
on exception (logging NOT a drain per the user's principle 2026-06-17).
The legacy _detect_refresh_rate_win32() wrapper preserves its signature and
delegates to the helper. The call site in App.__init__ invokes the result
helper directly and drains errors to self._startup_timeline_errors.
Tests: 2 new tests (test_phase_10_l216_detect_refresh_rate_win32_result_success,
test_phase_10_l216_detect_refresh_rate_win32_result_failure) verify both paths.
Audit: L216 reclassified from INTERNAL_SILENT_SWALLOW (12 sites remaining,
was 13). New helper L219 is INTERNAL_COMPLIANT.
Migrate the imgui.save_ini_settings_to_memory try/except in
App._capture_workspace_profile (L897) to the canonical Result[T] pattern:
- Extract _capture_workspace_profile_ini_result(app) -> Result[str]
helper into Phase 8 Property Setter / State Result Helpers region.
- The legacy _capture_workspace_profile method calls the helper and
drains errors to app._last_request_errors (per FR-BC-4 event-handler
drain pattern; this is a property setter on the App).
- The original fallback behavior (ini = '' on failure) is preserved
so the legacy WorkspaceProfile still constructs with empty ini_content.
Tests:
- test_phase_8_l897_capture_workspace_profile_ini_result_success
- test_phase_8_l897_capture_workspace_profile_ini_result_failure
Audit: INTERNAL_BROAD_CATCH count in src/gui_2.py is now 0. All 22
INTERNAL_BROAD_CATCH sites originally in src/gui_2.py have been
migrated to Result[T] across Phases 3-8.
Migrate the ini-file-read try/except in App._diag_layout_state (L591) to
the canonical Result[T] pattern:
- Extract _diag_layout_state_ini_text_result(app, ini_path) -> Result[str]
helper into new Phase 8 Property Setter / State Result Helpers region.
- The legacy _diag_layout_state method calls the helper and drains errors
to app._startup_timeline_errors (the Phase 2 drain plane for startup
callbacks).
- The original fallback behavior (early return on read failure, stderr
write for visibility) is preserved.
Tests:
- test_phase_8_l591_diag_layout_state_ini_text_result_success
- test_phase_8_l591_diag_layout_state_ini_text_result_failure
Audit: INTERNAL_BROAD_CATCH count in src/gui_2.py dropped from 2 to 1
(remaining: L896 _capture_workspace_profile, formerly L897 in inventory).
Migrate the worker() closure in _check_auto_refresh_context_preview (L4321)
to the canonical Result[T] pattern:
- Extract _worker_context_preview_result(app) -> Result[None] helper into
new Phase 7 Worker/Background Result Helpers region.
- The legacy worker() wrapper calls the helper and drains errors to
app.controller._worker_errors (with controller._worker_errors_lock
acquired on append) per sub-track 3 Phase 6 Group 6.5 telemetry drain.
- The try/finally cleanup (setting _is_generating_preview=False and
handling _pending_preview_refresh) is preserved verbatim.
Tests:
- test_phase_7_l4321_worker_context_preview_result_success
- test_phase_7_l4321_worker_context_preview_result_failure
Audit: INTERNAL_BROAD_CATCH count in src/gui_2.py dropped from 3 to 2
(remaining: L591 _diag_layout_state, L897 _capture_workspace_profile).
The lock-protected append ensures thread-safety when multiple worker
threads call _report-style drains concurrently. The helper preserves
the original fallback behavior (app.context_preview_text =
'Error generating context preview.' on failure) so the user-visible
UX is unchanged.
Extract _render_context_batch_actions_preview_result helper from the
_do_generate preview try/except in render_context_batch_actions. The
imgui.button callback drains errors to app._last_request_errors per FR-BC-4
event-handler pattern.
[pre-audit] L3582 INTERNAL_BROAD_CATCH
[post-audit] V count: 8 -> 7 (L3582 removed)
Extract _render_tool_preset_bias_save_result helper from the BiasProfile
save try/except in render_tool_preset_manager_content. The imgui.button
callback drains errors to app._last_request_errors per FR-BC-4
event-handler pattern.
[pre-audit] L3163 INTERNAL_BROAD_CATCH
[post-audit] V count: 9 -> 8 (L3163 removed)
Extract request_patch_from_tier4_result helper from the
ai_client.run_tier4_patch_generation try/except in App.request_patch_from_tier4.
Legacy wrapper drains errors to app._last_request_errors per FR-BC-4
event-handler pattern.
[pre-audit] L1428 INTERNAL_BROAD_CATCH
[post-audit] V count: 10 -> 9 (L1428 removed)