From f7d703fd5bda1f902f1a44526fbaf56d0a5b51f2 Mon Sep 17 00:00:00 2001 From: "BLUDATA\\marcio.heiderscheidt" Date: Mon, 13 Apr 2026 14:18:09 -0300 Subject: [PATCH] fix: add logging on rejected transcript paths and platform-native path test - _count_human_messages() now logs a WARNING via _log() when a non-empty transcript_path is rejected by the validator, making silent auto-save failures diagnosable via hook.log - Add test for platform-native paths (backslashes on Windows) to verify _validate_transcript_path works cross-platform - Add test verifying the warning log is emitted on rejection Refs: MemPalace/mempalace#809 --- mempalace/hooks_cli.py | 6 +++++- tests/test_hooks_cli.py | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/mempalace/hooks_cli.py b/mempalace/hooks_cli.py index cc26058..14fd9f7 100644 --- a/mempalace/hooks_cli.py +++ b/mempalace/hooks_cli.py @@ -65,7 +65,11 @@ def _validate_transcript_path(transcript_path: str) -> Path: def _count_human_messages(transcript_path: str) -> int: """Count human messages in a JSONL transcript, skipping command-messages.""" path = _validate_transcript_path(transcript_path) - if path is None or not path.is_file(): + if path is None: + if transcript_path: + _log(f"WARNING: transcript_path rejected by validator: {transcript_path!r}") + return 0 + if not path.is_file(): return 0 count = 0 try: diff --git a/tests/test_hooks_cli.py b/tests/test_hooks_cli.py index 2c14ae0..861c054 100644 --- a/tests/test_hooks_cli.py +++ b/tests/test_hooks_cli.py @@ -462,6 +462,27 @@ def test_count_rejects_traversal_path(): assert _count_human_messages("../../etc/passwd") == 0 +def test_count_logs_warning_on_rejected_path(tmp_path): + """_count_human_messages should log a warning when a non-empty path is rejected.""" + with patch("mempalace.hooks_cli.STATE_DIR", tmp_path): + with patch("mempalace.hooks_cli._log") as mock_log: + _count_human_messages("../../etc/passwd") + mock_log.assert_called_once() + assert "rejected" in mock_log.call_args[0][0].lower() + + +def test_validate_transcript_accepts_platform_native_path(tmp_path): + """Validator accepts platform-native paths (backslashes on Windows, slashes on Unix).""" + session_file = tmp_path / "projects" / "abc123" / "session.jsonl" + session_file.parent.mkdir(parents=True) + session_file.touch() + # Use the OS-native string representation (backslashes on Windows) + result = _validate_transcript_path(str(session_file)) + assert result is not None + assert result.suffix == ".jsonl" + assert result.is_file() + + def test_stop_hook_rejects_injected_stop_hook_active(tmp_path): """stop_hook_active with shell injection string should not cause issues.""" transcript = tmp_path / "t.jsonl"