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).
Phase 9 = ai_client Batch A: 8 INTERNAL_BROAD_CATCH sites in src/ai_client.py.
ai_client is the AI provider SDK layer (Anthropic/Gemini/DeepSeek/MiniMax).
17 BC sites total (per Phase 1 audit); first 8 sites = Batch A.
The 4 BOUNDARY_SDK sites stay as-is (vendor SDK exceptions are converted).
The 4 INTERNAL_PROGRAMMER_RAISE sites stay as-is (raise AttributeError in
__getattr__ etc.). The 17 INTERNAL_COMPLIANT sites stay as-is.
The 9 INTERNAL_SILENT_SWALLOW and 7 INTERNAL_RETHROW sites are handled in
Phases 11 and 12 respectively.
Target: ai_client BC 17 -> 9 after Batch A.
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.
Re-read lines 462-540 (The Broad-Except Distinction), lines 625-690 (Re-Raise
Patterns), and the AI Agent Checklist. CRITICAL anti-sliming protocol:
Phase 8 = mcp_client silent-swallow + UNCLEAR (6 sites):
- 5 INTERNAL_SILENT_SWALLOW sites (bare-except or except+pass patterns)
- 1 UNCLEAR site
Plus 3 nested BC cleanup (1 _search_file in py_find_usages_result + 2 trace
in derive_code_path_result).
RULES (anti-sliming):
- NO narrowing+logging (narrow + sys.stderr.write / logging.error = STILL violation)
- NO silent recovery (except: pass = SILENT_SWALLOW violation)
- MUST use full Result[T] propagation up to a true drain point
- Logging is NOT a drain (per user's principle 2026-06-17)
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 7 = mcp_client Batch E: 8 more INTERNAL_BROAD_CATCH sites
- L1338 py_get_hierarchy, L1359 py_get_docstring
- L1383 derive_code_path, L1418 trace
- L1452 get_tree
- L1535 web_search, L1561 fetch_url, L1580 get_ui_performance
Target: mcp_client BC 9 -> 1 after Batch E (the _search_file nested try/except
is separate from these 8 Batch E sites; will be classified/fixed in Phase 8).
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.
Re-read lines 462-540 (The Broad-Except Distinction). Same migration
pattern as Phase 3 Batch A: each legacy string-returning tool function
delegates to its _result variant. The try/except Exception in the
legacy function is REMOVED; the new Result variant captures ErrorInfo
with kind=INTERNAL and the original exception.
Phase 4 = mcp_client Batch B: 8 INTERNAL_BROAD_CATCH sites (lines 473-593)
- L473 get_git_diff
- L492 ts_c_get_skeleton, L509 ts_c_get_code_outline, L523 ts_c_get_definition
- L537 ts_c_get_signature, L555 ts_c_update_definition
- L576 ts_cpp_get_skeleton, L593 ts_cpp_get_code_outline
Target: mcp_client BC 32 -> 24 after Batch B.
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.
Re-read in full (989 lines). Key sections reviewed for this track:
- The 5 Patterns (Nil-Sentinel, Zero-Init, Fail Early, AND over OR, Side-Channel)
- Drain Points section (the 5 patterns: HTTP error response, GUI error display,
intentional app termination, telemetry emission, bounded retry)
- The Broad-Except Distinction (broad+log = SILENT_SWALLOW violation)
- Re-Raise Patterns 1/2/3 (catch+convert, catch+log+reraise, catch+cleanup+reraise)
- AI Agent Checklist (5 MUST-DO + 7 MUST-NOT-DO + 3 boundary patterns)
- Rule #0: MUST READ THIS STYLEGUIDE FIRST
- The pre-commit gate (4 audit scripts in --strict mode)
Per Rule #0: this commit message acknowledges the read. The full styleguide
content was reviewed end-to-end before any code work in Phase 0.
Adds the end-of-track artifacts for the tier2_leak_prevention_20260620
fix track:
- docs/reports/TRACK_COMPLETION_tier2_leak_prevention_20260620.md:
Full track completion report following the precedent set by
TRACK_COMPLETION_tier2_autonomous_sandbox_20260616.md. Documents
the 4 atomic commits, the 25 default-on tests, the manual
end-to-end verification, the key design decisions (auto-unstage
not exit 1, git rm --cached --force, CRLF handling, specific not
prefix patterns), the known limitations, and the next steps for
the user (push to origin, rebase stale tier-2 branches, re-run
setup on the existing clone, optional CI wiring).
- conductor/tracks/tier2_leak_prevention_20260620/metadata.json:
Track metadata (status=shipped, scope: 5 new files + 1 modified,
25 default-on tests, 5 verification criteria, 5 risk-register
entries, 2 deferred follow-up tracks).
- conductor/tracks/tier2_leak_prevention_20260620/spec.md:
Track spec (background on the 00e5a3f2 offender commit, design
with the 3-layer defense-in-depth, forbidden patterns, tests,
out-of-scope items).
- conductor/tracks/tier2_leak_prevention_20260620/plan.md:
Track plan (4 phases: revert + hook + audit + install; tasks
recorded retroactively per workflow.md "Plan is the source of
truth").
- conductor/tracks/tier2_leak_prevention_20260620/state.toml:
Track state (status=completed, current_phase=complete, 4 phases
with checkpoint SHAs, 16 tasks all completed with commit SHAs).
- conductor/tracks.md: registered as track 6f in the Active
Tracks table; added a "Recently Completed" entry with the
commit-history summary.
Per conductor/workflow.md "End-of-track report" protocol. The
report includes a "Mistake to flag" section about the
`Remove-Item -Recurse -Force` accident during verification, per
the AGENTS.md "Hard ban on destructive commands" rule (which is
specifically about `git restore`/`git checkout`/`git reset`/`git
push` but the lesson generalizes: destructive PowerShell commands
on directories with tracked files require explicit verification
before running).