Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Gradata/src/gradata/hooks/session_close.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,9 +278,21 @@ def _run_cloud_sync(brain_dir: str, data: dict) -> None:
Claude Code never calls ``brain.end_session()`` directly, so
``_cloud_sync_session`` never fired from IDE sessions before this hook
path existed. Gated on GRADATA_API_KEY — no key, no sync, no network.

As of #194 day 4, Brain.correct() write-through is the default cloud
sync path. The session_close hook tick is redundant when write-through
is active and was double-writing every correction. Set
GRADATA_DISABLE_WRITE_THROUGH=1 to fall back to this legacy path.
"""
if not os.environ.get("GRADATA_API_KEY"):
return
# Default behavior: write-through covers it. Skip the legacy tick.
if os.environ.get("GRADATA_DISABLE_WRITE_THROUGH") != "1":
_log.info(
"write-through enabled, skipping legacy cloud sync from session_close "
"(set GRADATA_DISABLE_WRITE_THROUGH=1 to restore legacy behavior)"
)
return
try:
from gradata._core import cloud_sync_tick

Expand Down
42 changes: 42 additions & 0 deletions Gradata/tests/test_session_close_write_through_gate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""Test the GRADATA_DISABLE_WRITE_THROUGH gate on session_close cloud sync.

#194 day 4: Brain.correct() write-through is the default cloud sync path.
The session_close hook's legacy cloud_sync_tick is now skipped by default
to avoid double-writes. Only runs when GRADATA_DISABLE_WRITE_THROUGH=1.
"""

from __future__ import annotations

from unittest.mock import patch

from gradata.hooks import session_close


def test_run_cloud_sync_skipped_when_write_through_default(monkeypatch):
"""Default behavior: write-through covers it, session_close tick is skipped."""
monkeypatch.setenv("GRADATA_API_KEY", "gd_live_test")
monkeypatch.delenv("GRADATA_DISABLE_WRITE_THROUGH", raising=False)
with patch("gradata._core.cloud_sync_tick") as mock_tick:
session_close._run_cloud_sync("/tmp/fake-brain", {"session_number": 1})
(
mock_tick.assert_not_called(),
("session_close must NOT call cloud_sync_tick when write-through is on"),
)
Comment on lines +21 to +24
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
python - <<'PY'
import ast
from pathlib import Path

p = Path("Gradata/tests/test_session_close_write_through_gate.py")
tree = ast.parse(p.read_text(encoding="utf-8"))
for node in ast.walk(tree):
    if isinstance(node, ast.Expr) and isinstance(node.value, ast.Tuple):
        print(f"{p}:{node.lineno}:{node.col_offset} tuple-expression statement")
PY

Repository: Gradata/gradata

Length of output: 146


Remove the no-op tuple wrapper around assert_not_called().

This tuple expression serves no purpose and obfuscates the assertion.

Suggested diff
-    (
-        mock_tick.assert_not_called(),
-        ("session_close must NOT call cloud_sync_tick when write-through is on"),
-    )
+    mock_tick.assert_not_called()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Gradata/tests/test_session_close_write_through_gate.py` around lines 21 - 24,
Remove the redundant tuple expression wrapping mock_tick.assert_not_called() in
the test; replace the tuple (mock_tick.assert_not_called(), ("session_close must
NOT call cloud_sync_tick when write-through is on")) with a direct assertion
call and, if a message is desired, use the testing framework's assertion API
(i.e., call mock_tick.assert_not_called() directly or use an explicit assert
with the message) so the test invokes mock_tick.assert_not_called() rather than
creating a no-op tuple; locate the call near the session_close test referencing
mock_tick and cloud_sync_tick.



def test_run_cloud_sync_invoked_when_write_through_disabled(monkeypatch):
"""Opt-out via GRADATA_DISABLE_WRITE_THROUGH=1: legacy path runs."""
monkeypatch.setenv("GRADATA_API_KEY", "gd_live_test")
monkeypatch.setenv("GRADATA_DISABLE_WRITE_THROUGH", "1")
with patch("gradata._core.cloud_sync_tick") as mock_tick:
session_close._run_cloud_sync("/tmp/fake-brain", {"session_number": 1})
mock_tick.assert_called_once_with("/tmp/fake-brain", 1)


def test_run_cloud_sync_skipped_when_no_api_key(monkeypatch):
"""No API key: never call cloud regardless of write-through state."""
monkeypatch.delenv("GRADATA_API_KEY", raising=False)
monkeypatch.setenv("GRADATA_DISABLE_WRITE_THROUGH", "1")
with patch("gradata._core.cloud_sync_tick") as mock_tick:
session_close._run_cloud_sync("/tmp/fake-brain", {"session_number": 1})
mock_tick.assert_not_called()
Loading