diff --git a/src/audit.py b/src/audit.py index c0ecb61..c13cd22 100644 --- a/src/audit.py +++ b/src/audit.py @@ -57,6 +57,15 @@ _LOG_PATH: Path | None = None _SESSION_ID: str | None = None _SESSION_STARTED: bool = False +# Kill switch — when True, every log_* function is a no-op. Set to +# True while bisecting a "blank pages" report where ``open()`` inside +# the log writer was suspected of blocking on the user's filesystem +# (Windows + antivirus + ``~/.datatools/logs/``). A blocking ``open`` +# call doesn't raise so try/except can't recover it; the only safe +# bisect is "don't touch the disk at all." Toggle back to False once +# the user confirms pages render. +_DISABLED: bool = True + def audit_log_dir() -> Path: """Return the directory where audit logs are written. @@ -147,6 +156,8 @@ def log_event( Failures are swallowed silently — a broken audit log must not take the GUI down. """ + if _DISABLED: + return try: event = { "ts": datetime.now(tz=timezone.utc).isoformat(timespec="milliseconds"), @@ -172,6 +183,8 @@ def log_event( def log_session_start() -> None: """Write the session-start banner. Idempotent within one process.""" + if _DISABLED: + return global _SESSION_STARTED with _LOCK: if _SESSION_STARTED: @@ -222,6 +235,8 @@ def log_page_open(slug: str) -> None: Whole body is wrapped in try/except — the audit log is best- effort and MUST NOT crash the page that called it. """ + if _DISABLED: + return try: try: import streamlit as st