Follow-up to the traceback gate: client-facing exception detail is now gated too.
- safe_error(e) (app/utils/security.py): returns the exception string only when
FLASK_DEBUG, otherwise a generic message. Full detail stays in server logs.
- All catch-all `except Exception` handlers in api/{graph,report,simulation}.py now
return safe_error(e) instead of str(e); same for the persisted error fields
(project.error / state.error / task fail messages). Typed `except ValueError`
validation handlers (404/400) keep str(e) — those are intentional, actionable
user messages that echo only user-supplied ids.
- graph_builder no longer puts a full traceback into the task error (logs it
server-side with exc_info, surfaces safe_error to the client); the batch-failure
progress message is gated too.
- README documents the CSP connect-src ↔ VITE_API_BASE_URL coupling.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>