fix: auto-export AGENTS.md after graduation#249
Conversation
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
📝 WalkthroughSummary
WalkthroughWhen lessons graduate from PATTERN to RULE during session end, the brain now automatically exports an AGENTS.md file containing the promoted rules. The graduation writer persists both active and graduated lessons, triggers the export with error suppression, and the session end returns an ChangesAuto-export AGENTS.md on lesson graduation
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 OpenGrep (1.22.0)OpenGrep fatal error (exit code 2): �[32m✔�[39m �[1mOpengrep OSS�[0m �[1m Loading rules from local config...�[0m Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with 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.
Inline comments:
In `@Gradata/src/gradata/hooks/session_close.py`:
- Line 110: The hook currently writes lessons.md directly with
lessons_path.write_text(format_lessons(all_lessons), ...) which risks partial
files; replace this direct write with the atomic helper
gradata._db.write_lessons_safe and pass the target path and the formatted
lessons content (i.e., call write_lessons_safe(lessons_path,
format_lessons(all_lessons))) so lessons are written atomically; ensure you
import or reference gradata._db.write_lessons_safe where the hook uses
lessons_path and format_lessons.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 9574e91f-5d0c-4588-bde0-3303b1e63a73
📒 Files selected for processing (4)
Gradata/src/gradata/_core.pyGradata/src/gradata/hooks/session_close.pyGradata/tests/test_graduation_notification.pyGradata/tests/test_session_close_write_through_gate.py
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: pytest ubuntu-latest / py3.11
- GitHub Check: pytest windows-latest / py3.12
- GitHub Check: pytest macos-latest / py3.12
- GitHub Check: pytest macos-latest / py3.11
- GitHub Check: pytest ubuntu-latest / py3.12
- GitHub Check: pytest windows-latest / py3.11
- GitHub Check: pytest (py3.11)
- GitHub Check: pytest (py3.12)
🧰 Additional context used
📓 Path-based instructions (2)
Gradata/tests/**/*.py
📄 CodeRabbit inference engine (Gradata/AGENTS.md)
Gradata/tests/**/*.py: SetBRAIN_DIRenvironment variable viatmp_pathin conftest.py for test isolation — ensure_paths.pymodule cache refreshes when callingBrain.init()directly inside tests
Add unit tests intests/test_*.pyfor every CI push without LLM calls (deterministic); mark integration tests with@pytest.mark.integrationand skip them by default (they hit real LLM APIs)
Files:
Gradata/tests/test_graduation_notification.pyGradata/tests/test_session_close_write_through_gate.py
Gradata/src/**/*.py
📄 CodeRabbit inference engine (Gradata/AGENTS.md)
Gradata/src/**/*.py: Prefersentence-transformersfor local embeddings,google-genaifor Gemini embeddings,cryptographyfor AES-GCM encrypted system.db,bm25sfor BM25 rule ranking, andmem0aifor external memory adapters — guard all optional dependency imports withtry / except ImportErrorat the call site, never at module level
Maintain strict layering: Layer 0 (Primitives: _types.py, _db.py, _events.py, _paths.py, _file_lock.py; Patterns: contrib/patterns/) must never import from Layer 1 (Enhancements: enhancements/, rules/) or Layer 2 (Public API: brain.py, cli.py, daemon.py, mcp_server.py)
Never use bareexcept: pass— use typed exceptions or at minimumlogger.warning(...)withexc_info=Trueto avoid silent failure in a memory product
Never import from out-of-scope sibling directories../Sprites/or../Hausgem/withingradata/*code — that is a layering bug
Never leak private-sibling paths into public docs/code — no references to../Sprites/,../Hausgem/, email addresses, OneDrive paths, or Sprites-specific examples from insidegradata/*
Use atomic-write helper when writing JSON files to prevent corruption from mid-write crashes
Files:
Gradata/src/gradata/_core.pyGradata/src/gradata/hooks/session_close.py
🧠 Learnings (3)
📓 Common learnings
Learnt from: Gradata
Repo: Gradata/gradata PR: 0
File: :0-0
Timestamp: 2026-04-17T17:18:07.439Z
Learning: In PR `#102` (gradata/gradata), Round 2 addressed: cli.py env-first brain resolution (GRADATA_BRAIN > --brain-dir > cwd), _tenant.py corrupt .tenant_id overwrite, _env_int default clamping to minimum, and _events.py tenant-scoped fallback SELECT for dedup. All ruff and 99 tests green after these fixes.
📚 Learning: 2026-05-01T15:50:32.772Z
Learnt from: CR
Repo: Gradata/gradata PR: 0
File: Gradata/AGENTS.md:0-0
Timestamp: 2026-05-01T15:50:32.772Z
Learning: Applies to Gradata/tests/**/*.py : Add unit tests in `tests/test_*.py` for every CI push without LLM calls (deterministic); mark integration tests with `pytest.mark.integration` and skip them by default (they hit real LLM APIs)
Applied to files:
Gradata/tests/test_graduation_notification.py
📚 Learning: 2026-05-01T15:50:32.772Z
Learnt from: CR
Repo: Gradata/gradata PR: 0
File: Gradata/AGENTS.md:0-0
Timestamp: 2026-05-01T15:50:32.772Z
Learning: Applies to Gradata/tests/**/*.py : Set `BRAIN_DIR` environment variable via `tmp_path` in conftest.py for test isolation — ensure `_paths.py` module cache refreshes when calling `Brain.init()` directly inside tests
Applied to files:
Gradata/tests/test_session_close_write_through_gate.py
🔇 Additional comments (5)
Gradata/src/gradata/_core.py (2)
1017-1033: LGTM!
1146-1146: LGTM!Gradata/src/gradata/hooks/session_close.py (1)
111-121: LGTM!Gradata/tests/test_session_close_write_through_gate.py (1)
10-10: LGTM!Also applies to: 46-66
Gradata/tests/test_graduation_notification.py (1)
158-185: LGTM!
| lessons_path.write_text(format_lessons(active), encoding="utf-8") | ||
| active, graduated = graduate(lessons) | ||
| all_lessons = active + graduated | ||
| lessons_path.write_text(format_lessons(all_lessons), encoding="utf-8") |
There was a problem hiding this comment.
Use atomic-write helper for lessons.md to prevent corruption.
The codebase provides gradata._db.write_lessons_safe() specifically to prevent mid-write corruption of lessons.md (used in _core.py at lines 630, 1015). This hook writes lessons using direct write_text(), which can leave a partial file if the process crashes mid-write.
🛡️ Proposed fix
+from gradata._db import write_lessons_safe
+
def _run_graduation(brain_dir: str) -> None:
try:
from gradata.enhancements.self_improvement import format_lessons, graduate, parse_lessons
lessons_path = Path(brain_dir) / "lessons.md"
if not lessons_path.is_file():
return
text = lessons_path.read_text(encoding="utf-8")
lessons = parse_lessons(text)
if not lessons:
return
active, graduated = graduate(lessons)
all_lessons = active + graduated
- lessons_path.write_text(format_lessons(all_lessons), encoding="utf-8")
+ write_lessons_safe(lessons_path, format_lessons(all_lessons))🤖 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/src/gradata/hooks/session_close.py` at line 110, The hook currently
writes lessons.md directly with
lessons_path.write_text(format_lessons(all_lessons), ...) which risks partial
files; replace this direct write with the atomic helper
gradata._db.write_lessons_safe and pass the target path and the formatted
lessons content (i.e., call write_lessons_safe(lessons_path,
format_lessons(all_lessons))) so lessons are written atomically; ensure you
import or reference gradata._db.write_lessons_safe where the hook uses
lessons_path and format_lessons.
Summary
gradata exportstep required.brain_end_sessionto rewriteAGENTS.mdfrom canonical RULE-tier lessons after successful graduation persistence.AGENTS.mdtoo.AGENTS.mdidempotently.Verification
python3 -m pytest tests/test_graduation_notification.py::test_rule_graduation_auto_exports_agents_md tests/test_session_close_write_through_gate.py::test_run_graduation_exports_agents_md_for_new_rule tests/test_rule_export.py -q23 passed in 3.24s/home/olive/.local/bin/uvx ruff check src/gradata/_core.py src/gradata/hooks/session_close.py tests/test_graduation_notification.py tests/test_session_close_write_through_gate.pyAll checks passed!git diff --checkCloses GRA-27