From 21f2248a3c41dae53ba596121ef83413a7c6cb8f Mon Sep 17 00:00:00 2001 From: Igor Lins e Silva <4753812+igorls@users.noreply.github.com> Date: Tue, 7 Apr 2026 17:21:37 -0300 Subject: [PATCH 1/3] fix: enable SQLite WAL mode and add consistent LIMIT to KG timeline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Enable WAL journal mode in _conn() for better concurrent read performance and reduced SQLITE_BUSY risk - Add LIMIT 100 to entity-filtered timeline query (was unbounded, while global timeline already had LIMIT 100) Findings: #8 (HIGH — no WAL mode), #22 (LOW — inconsistent limits) Includes test infrastructure from PR #131. 92 tests pass. --- mempalace/knowledge_graph.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mempalace/knowledge_graph.py b/mempalace/knowledge_graph.py index a2f8b54..226c92d 100644 --- a/mempalace/knowledge_graph.py +++ b/mempalace/knowledge_graph.py @@ -87,7 +87,9 @@ class KnowledgeGraph: conn.close() def _conn(self): - return sqlite3.connect(self.db_path, timeout=10) + conn = sqlite3.connect(self.db_path, timeout=10) + conn.execute("PRAGMA journal_mode=WAL") + return conn def _entity_id(self, name: str) -> str: return name.lower().replace(" ", "_").replace("'", "") @@ -284,6 +286,7 @@ class KnowledgeGraph: JOIN entities o ON t.object = o.id WHERE (t.subject = ? OR t.object = ?) ORDER BY t.valid_from ASC NULLS LAST + LIMIT 100 """, (eid, eid), ).fetchall() From b45bff9db189ee1f7e412e4a61257e089b04819d Mon Sep 17 00:00:00 2001 From: Igor Lins e Silva <4753812+igorls@users.noreply.github.com> Date: Tue, 7 Apr 2026 17:30:51 -0300 Subject: [PATCH 2/3] test: add WAL mode and entity timeline limit assertions --- tests/test_knowledge_graph.py | 17 +++++++++++++++++ uv.lock | 10 ++++++++++ 2 files changed, 27 insertions(+) diff --git a/tests/test_knowledge_graph.py b/tests/test_knowledge_graph.py index a8fcd9a..d7d9838 100644 --- a/tests/test_knowledge_graph.py +++ b/tests/test_knowledge_graph.py @@ -107,6 +107,23 @@ class TestTimeline: tl = kg.timeline() assert len(tl) == 100 # LIMIT 100 + def test_timeline_entity_has_limit(self, kg): + # Add > 100 triples all connected to a single entity + for i in range(105): + kg.add_triple( + "hub", "connects_to", f"spoke_{i}", valid_from=f"2025-01-{(i % 28) + 1:02d}" + ) + tl = kg.timeline("hub") + assert len(tl) == 100 # LIMIT 100 on entity-filtered branch + + +class TestWALMode: + def test_wal_mode_enabled(self, kg): + conn = kg._conn() + mode = conn.execute("PRAGMA journal_mode").fetchone()[0] + conn.close() + assert mode == "wal" + class TestStats: def test_stats_empty(self, kg): diff --git a/uv.lock b/uv.lock index 0b00717..9d99313 100644 --- a/uv.lock +++ b/uv.lock @@ -966,6 +966,13 @@ dependencies = [ { name = "pyyaml" }, ] +[package.optional-dependencies] +dev = [ + { name = "pytest", version = "8.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "pytest", version = "9.0.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "ruff" }, +] + [package.dev-dependencies] dev = [ { name = "pytest", version = "8.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, @@ -976,8 +983,11 @@ dev = [ [package.metadata] requires-dist = [ { name = "chromadb", specifier = ">=0.4.0,<1" }, + { name = "pytest", marker = "extra == 'dev'", specifier = ">=7.0" }, { name = "pyyaml", specifier = ">=6.0" }, + { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.4.0" }, ] +provides-extras = ["dev"] [package.metadata.requires-dev] dev = [ From 6fa985eac2f86aff88f21b66fe35edf81f06611c Mon Sep 17 00:00:00 2001 From: Igor Lins e Silva <4753812+igorls@users.noreply.github.com> Date: Tue, 7 Apr 2026 18:58:20 -0300 Subject: [PATCH 3/3] fix: update dialect tests for PR #147 stats API and remove unused fixture param --- tests/conftest.py | 2 +- tests/test_dialect.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index d0c30c2..22b5e42 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -35,7 +35,7 @@ from mempalace.knowledge_graph import KnowledgeGraph # noqa: E402 @pytest.fixture(scope="session", autouse=True) -def _isolate_home(tmp_path_factory): +def _isolate_home(): """Ensure HOME points to a temp dir for the entire test session. The env vars were already set at module level (above) so that diff --git a/tests/test_dialect.py b/tests/test_dialect.py index 2ef1df6..8edc7ec 100644 --- a/tests/test_dialect.py +++ b/tests/test_dialect.py @@ -109,11 +109,11 @@ class TestCompressionStats: original = "We decided to use GraphQL instead of REST. " * 10 compressed = d.compress(original) stats = d.compression_stats(original, compressed) - assert stats["ratio"] > 1 - assert stats["original_chars"] > stats["compressed_chars"] + assert stats["size_ratio"] > 1 + assert stats["original_chars"] > stats["summary_chars"] def test_count_tokens(self): - assert Dialect.count_tokens("hello world") == len("hello world") // 3 + assert Dialect.count_tokens("hello world") == 2 class TestZettelEncoding: