You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Timing-sensitive tests exposed by faster test suite (post-#938): circular-relations batch indexing, mcp sse routing #940
While landing #938 (which removes the implicit per-sync embedding delay from all non-semantic tests), two tests failed once each on single CI matrix legs while passing on all other legs and locally (8/8 repeats):
`tests/sync/test_sync_service.py::test_sync_entity_circular_relations` — failed on SQLite Unit (depot, Python 3.12) with `len(entity_b.outgoing_relations) == 0`. The test awaits `sync()` which awaits `resolve_relations()` inline, so the suspect is concurrent batch indexing (`_index_changed_files` / `BatchIndexer`): on a 2-core runner, B's relation to A can go pending during parallel indexing and apparently is not always picked up by the final resolve pass. The embedding work previously serialized/slowed this path enough to mask it.
`test-int/cli/test_routing_integration.py::TestMcpCommandRouting::test_mcp_sse_forces_local` — failed on SQLite Integration (depot, Python 3.14) with `KeyError: 'FORCE_LOCAL'` (the mocked `mcp_server.run` never executed, i.e. `runner.invoke` died before reaching it). Passed on 3.12/3.13 and locally on 3.14.5.
Neither reproduces locally. Both smell like real (if narrow) races worth a look rather than blind `@pytest.mark.flaky` decoration — especially #1, which implies a user-visible window where a synced note's relations are unresolved.
Classify issue type and assess priority/complexity
Check for duplicates
Apply appropriate labels
Provide triage summary
Analysis
No duplicates found. The bug label is already applied. Additional labels (testing, sync, mcp, complex) don't exist in the repo yet, so they can't be applied automatically — worth creating if the project adds more label taxonomy over time.
Bug 1 — test_sync_entity_circular_relations (Race in batch relation resolution)
Type: Bug | Priority: Medium | Component: sync/database | Complexity: Medium
Root cause: The failure (len(entity_b.outgoing_relations) == 0) is a genuine ordering race in _index_changed_files → batch_indexer.index_files. When entity_a.md and entity_b.md land in the same batch:
Both are indexed concurrently via asyncio.gather (up to index_entity_max_concurrent)
Each entity's inline resolve_relations=True pass runs while the other entity may not be committed yet
If entity_b is indexed before entity_a, B's relation depends_on [[concept/entity-a]] is stored with to_id=NULL (pending)
The sync-level resolve_relations() at sync_service.py:385should pick this up, but on a 2-core CI runner under load, there appears to be a window where the pending row isn't visible or the final resolve runs before B's row is fully committed to WAL
User impact: Real — a user syncing two files with circular references could see missing relations in the knowledge graph until the next sync cycle triggers another resolve_relations pass.
Potential fix directions:
In resolve_relations(), re-query after resolution to verify forward references were all resolved, retrying if any remain (a second pass is cheap)
Ensure the sync-level resolve_relations() call runs strictly after all batch DB commits flush — add an explicit await session.flush() or similar barrier before the resolve pass
Add a post-condition assertion in SyncService.sync() that all relations are resolved (catches this in integration tests)
Root cause:KeyError: 'FORCE_LOCAL' means env_at_run dict is empty — mock_run was never called. runner.invoke (Typer/Click's CliRunner) swallows exceptions by default. Something is raising before mcp_server.run() is reached at mcp.py:121-128.
The command path for --transport sse:
Lines 58–61: set env vars ✓ (safe)
Lines 66–68: import basic_memory.mcp.tools/prompts/resources — heavy imports, could have Python 3.14 compatibility issues
Line 71: init_mcp_logging() — mocked to lambda: None ✓
Lines 109–111: maybe_install_uvloop(ConfigManager().config) — creates a ConfigManager; might fail if config path doesn't exist in the integration test env on Python 3.14
The passing test test_mcp_streamable_http_forces_local uses the same code path — the difference is module import caching. If a prior test in the class already imported basic_memory.mcp.tools, it's cached and doesn't re-execute. The SSE test might run in a different order on Python 3.14 where something in the fresh import fails.
Immediate fix: Add result = runner.invoke(cli_app, ["mcp", "--transport", "sse"], catch_exceptions=False) to surface the real exception instead of silently returning an empty env_at_run. Or add assert result.exception is None before the env_at_run assertions, so the failure message shows the actual exception traceback.
This won't fix the underlying 3.14 compatibility issue but will make the failure diagnosable in CI.
User impact: Low — only affects the basic-memory mcp --transport sse startup path, and only on Python 3.14 under specific import ordering conditions.
Recommended Next Steps
#
Action
Effort
1
Add catch_exceptions=False (or assert result.exception is None) to test_mcp_sse_forces_local to expose the real Python 3.14 exception
Small
2
Add a defensive second-pass check in SyncService.resolve_relations() or a post-sync assertion that all pending relations are resolved
Medium
3
Investigate whether maybe_install_uvloop / heavy mcp imports in the mcp command body need Python 3.14 compatibility fixes
Medium
4
Consider extracting the mcp command body's imports into a fixture or lazy-loading pattern to make the test more hermetic
Activity
claude commentedon Jun 10, 2026
Claude finished @phernandez's task in 3m 32s —— View job
Issue Triage
Analysis
No duplicates found. The
buglabel is already applied. Additional labels (testing,sync,mcp,complex) don't exist in the repo yet, so they can't be applied automatically — worth creating if the project adds more label taxonomy over time.Bug 1 —
test_sync_entity_circular_relations(Race in batch relation resolution)Type: Bug | Priority: Medium | Component: sync/database | Complexity: Medium
Root cause: The failure (
len(entity_b.outgoing_relations) == 0) is a genuine ordering race in_index_changed_files→batch_indexer.index_files. When entity_a.md and entity_b.md land in the same batch:asyncio.gather(up toindex_entity_max_concurrent)resolve_relations=Truepass runs while the other entity may not be committed yetdepends_on [[concept/entity-a]]is stored withto_id=NULL(pending)resolve_relations()atsync_service.py:385should pick this up, but on a 2-core CI runner under load, there appears to be a window where the pending row isn't visible or the final resolve runs before B's row is fully committed to WALUser impact: Real — a user syncing two files with circular references could see missing relations in the knowledge graph until the next sync cycle triggers another
resolve_relationspass.Potential fix directions:
resolve_relations(), re-query after resolution to verify forward references were all resolved, retrying if any remain (a second pass is cheap)resolve_relations()call runs strictly after all batch DB commits flush — add an explicitawait session.flush()or similar barrier before the resolve passSyncService.sync()that all relations are resolved (catches this in integration tests)Bug 2 —
test_mcp_sse_forces_local(Python 3.14 KeyError before mock reachesmcp_server.run)Type: Bug | Priority: Low-Medium | Component: mcp/cli | Complexity: Medium
Root cause:
KeyError: 'FORCE_LOCAL'meansenv_at_rundict is empty —mock_runwas never called.runner.invoke(Typer/Click'sCliRunner) swallows exceptions by default. Something is raising beforemcp_server.run()is reached atmcp.py:121-128.The command path for
--transport sse:import basic_memory.mcp.tools/prompts/resources— heavy imports, could have Python 3.14 compatibility issuesinit_mcp_logging()— mocked tolambda: None✓maybe_install_uvloop(ConfigManager().config)— creates aConfigManager; might fail if config path doesn't exist in the integration test env on Python 3.14The passing test
test_mcp_streamable_http_forces_localuses the same code path — the difference is module import caching. If a prior test in the class already importedbasic_memory.mcp.tools, it's cached and doesn't re-execute. The SSE test might run in a different order on Python 3.14 where something in the fresh import fails.Immediate fix: Add
result = runner.invoke(cli_app, ["mcp", "--transport", "sse"], catch_exceptions=False)to surface the real exception instead of silently returning an emptyenv_at_run. Or addassert result.exception is Nonebefore theenv_at_runassertions, so the failure message shows the actual exception traceback.This won't fix the underlying 3.14 compatibility issue but will make the failure diagnosable in CI.
User impact: Low — only affects the
basic-memory mcp --transport ssestartup path, and only on Python 3.14 under specific import ordering conditions.Recommended Next Steps
catch_exceptions=False(or assertresult.exception is None) totest_mcp_sse_forces_localto expose the real Python 3.14 exceptionSyncService.resolve_relations()or a post-sync assertion that all pending relations are resolvedmaybe_install_uvloop/ heavy mcp imports in themcpcommand body need Python 3.14 compatibility fixesmcpcommand body's imports into a fixture or lazy-loading pattern to make the test more hermetictest(sync): quarantine circular-relations test in CI pending #940
test(sync): quarantine circular-relations test in CI pending #940
fix(sync): serialize in-memory SQLite sessions so concurrent rollback…
fix(cli): write config.json atomically and isolate auto-update in mcp…