-
-
Notifications
You must be signed in to change notification settings - Fork 147
fix(memory): restore beam initialization lifecycle #470
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -952,6 +952,52 @@ def test_sleep_consolidated_content_is_recallable(self, temp_db, monkeypatch): | |
|
|
||
|
|
||
| class TestMnemosyneIntegration: | ||
| def test_constructor_wires_beam_before_close(self, temp_db, monkeypatch): | ||
| """A close lifecycle must not move BEAM initialization into __del__.""" | ||
| mem = Mnemosyne(session_id="lifecycle", db_path=temp_db) | ||
| assert isinstance(mem.beam, BeamMemory) | ||
| assert mem.beam._event_emitter == mem._stream_emit | ||
|
|
||
| delivered = [] | ||
| monkeypatch.setattr(mem.stream, "emit", delivered.append) | ||
| mem.enable_streaming() | ||
| event = object() | ||
| assert mem.beam._event_emitter is not None | ||
| mem.beam._event_emitter(event) | ||
| assert delivered == [event] | ||
|
|
||
| mem.close() | ||
| mem.close() # Idempotent cleanup is safe for callers and __del__. | ||
|
|
||
| successor = Mnemosyne(session_id="successor", db_path=temp_db) | ||
| assert isinstance(successor.beam, BeamMemory) | ||
| successor.close() | ||
|
|
||
| def test_close_keeps_shared_beam_connection_for_live_instance(self, temp_db): | ||
| first = Mnemosyne(session_id="first", db_path=temp_db) | ||
| second = Mnemosyne(session_id="second", db_path=temp_db) | ||
|
|
||
| first.close() | ||
| assert second.beam.conn.execute("SELECT 1").fetchone()[0] == 1 | ||
| second.close() | ||
|
|
||
| def test_constructor_failure_releases_provisional_connection(self, temp_db, monkeypatch): | ||
| import mnemosyne.core.memory as memory_module | ||
|
|
||
| real_beam = memory_module.BeamMemory | ||
|
|
||
| def fail_beam(*args, **kwargs): | ||
| raise RuntimeError("beam construction failed") | ||
|
|
||
| monkeypatch.setattr(memory_module, "BeamMemory", fail_beam) | ||
| with pytest.raises(RuntimeError, match="beam construction failed"): | ||
| Mnemosyne(session_id="broken", db_path=temp_db) | ||
|
|
||
| monkeypatch.setattr(memory_module, "BeamMemory", real_beam) | ||
| recovered = Mnemosyne(session_id="recovered", db_path=temp_db) | ||
| assert isinstance(recovered.beam, BeamMemory) | ||
| recovered.close() | ||
|
Comment on lines
+976
to
+999
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Make the lifecycle tests prove both resources are released. The shared-instance test checks only
As per path instructions, tests require comprehensive coverage and meaningful assertions rather than merely successful reconstruction. 🧰 Tools🪛 Ruff (0.15.21)[warning] 989-989: Missing return type annotation for private function Add return type annotation: (ANN202) [warning] 989-989: Missing type annotation for (ANN002) [warning] 989-989: Unused function argument: (ARG001) [warning] 989-989: Missing type annotation for (ANN003) [warning] 989-989: Unused function argument: (ARG001) [warning] 990-990: Avoid specifying long messages outside the exception class (TRY003) 🤖 Prompt for AI AgentsSource: Path instructions |
||
|
|
||
| def test_legacy_and_beam_dual_write(self, temp_db): | ||
| mem = Mnemosyne(session_id="s2", db_path=temp_db) | ||
| mid = mem.remember("Likes pizza", source="preference", importance=0.8) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift
Align per-database ownership with per-database connection storage.
The refcounts distinguish databases, but each module retains only one thread-local connection. Switching databases displaces the prior handles, and final-owner cleanup cannot find them.
mnemosyne/core/memory.py#L30-L31: store connection ownership alongside actual per-path handles.mnemosyne/core/memory.py#L82-L136: resolve and close the handle associated with the released owner key.mnemosyne/core/memory.py#L240-L286: retain per-instance/per-path handles through acquisition and final release.mnemosyne/core/beam.py#L490-L507: replace the single cache slot with path-addressable BEAM connections.As per path instructions, verify cache invalidation correctness and lifecycle cleanup for BEAM and core memory.
📍 Affects 2 files
mnemosyne/core/memory.py#L30-L31(this comment)mnemosyne/core/memory.py#L82-L136mnemosyne/core/memory.py#L240-L286mnemosyne/core/beam.py#L490-L507🤖 Prompt for AI Agents
Source: Path instructions