mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
fix(core): preserve an existing database default when repairing a missing config default
Follow-up to #985 (the #974 fix by @rudi193-cmd), addressing the codex P2 raised on #987: when config's default_project has no database row but the database still holds a valid default of its own, promoting the just-added project would silently steal that default. The repair now repoints config at a surviving database default — matching synchronize_projects, which treats the database default as authoritative — and promotes the added project only when no usable database default exists (no default at all, or one unknown to config, which set_default_project rejects and reconciliation deletes). Also removes an unused ProjectConfig import from the #985 regression test (strict ruff failure; CI's --fix lint masked it). Refs #974 Signed-off-by: phernandez <paul@basicmachines.co>
This commit is contained in:
committed by
Paul Hernandez
parent
25732b2fe2
commit
32a1c208b3
@@ -261,14 +261,36 @@ class ProjectService:
|
||||
if config_default is not None:
|
||||
db_default_project = await self.repository.get_by_name(config_default)
|
||||
if db_default_project is None:
|
||||
await self.repository.set_as_default(created_project.id)
|
||||
self.config_manager.set_default_project(name)
|
||||
logger.info(
|
||||
"Promoted project '%s' to default because configured default '%s' "
|
||||
"is missing from database",
|
||||
name,
|
||||
config_default,
|
||||
)
|
||||
# Trigger: config names a default project that has no database row
|
||||
# (the fresh-config wedge from issue #974).
|
||||
# Why: synchronize_projects treats an existing database default as
|
||||
# authoritative, so a surviving default must win over promoting
|
||||
# the just-added project. set_default_project raises for names
|
||||
# absent from config — and reconciliation deletes such rows —
|
||||
# so a database default unknown to config cannot be repointed to.
|
||||
# Outcome: config is repointed at a usable database default when one
|
||||
# exists; otherwise the added project becomes the default.
|
||||
db_default = await self.repository.get_default_project()
|
||||
if (
|
||||
db_default is not None
|
||||
and self.config_manager.get_project(db_default.name)[0] is not None
|
||||
):
|
||||
self.config_manager.set_default_project(db_default.name)
|
||||
logger.info(
|
||||
"Repointed config default from missing '%s' at existing "
|
||||
"database default '%s'",
|
||||
config_default,
|
||||
db_default.name,
|
||||
)
|
||||
else:
|
||||
await self.repository.set_as_default(created_project.id)
|
||||
self.config_manager.set_default_project(name)
|
||||
logger.info(
|
||||
"Promoted project '%s' to default because configured default '%s' "
|
||||
"is missing from database",
|
||||
name,
|
||||
config_default,
|
||||
)
|
||||
|
||||
logger.info(f"Project '{name}' added at {resolved_path}")
|
||||
|
||||
|
||||
@@ -440,7 +440,7 @@ async def test_add_project_promotes_when_config_default_missing_from_db(
|
||||
):
|
||||
"""Regression #974: config default exists only in config, not DB — promote on add."""
|
||||
from basic_memory import config as config_module
|
||||
from basic_memory.config import ProjectConfig, ProjectEntry
|
||||
from basic_memory.config import ProjectEntry
|
||||
from basic_memory.markdown.entity_parser import EntityParser
|
||||
from basic_memory.markdown.markdown_processor import MarkdownProcessor
|
||||
from basic_memory.repository.project_repository import ProjectRepository
|
||||
@@ -480,6 +480,52 @@ async def test_add_project_promotes_when_config_default_missing_from_db(
|
||||
assert await repo.get_by_name("main") is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_add_project_preserves_existing_db_default(
|
||||
project_service: ProjectService, config_manager: ConfigManager, test_project
|
||||
):
|
||||
"""The #974 repair must not steal an existing database default.
|
||||
|
||||
Drift state: config's default_project names a project with no database row,
|
||||
but the database still holds a valid default of its own. synchronize_projects
|
||||
resolves this by trusting the database default, so add_project's repair must
|
||||
repoint config at it rather than promoting the just-added project.
|
||||
"""
|
||||
config_default = config_manager.default_project
|
||||
assert config_default is not None
|
||||
|
||||
surviving_name = f"test-surviving-default-{os.urandom(4).hex()}"
|
||||
added_name = f"test-no-steal-{os.urandom(4).hex()}"
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
surviving_path = str(Path(temp_dir) / "surviving")
|
||||
os.makedirs(surviving_path, exist_ok=True)
|
||||
|
||||
# A normally-added project that then becomes the database default,
|
||||
# while config's default_project still names the fixture project.
|
||||
await project_service.add_project(surviving_name, surviving_path)
|
||||
surviving = await project_service.repository.get_by_name(surviving_name)
|
||||
assert surviving is not None
|
||||
await project_service.repository.set_as_default(surviving.id)
|
||||
|
||||
# Wedge config: its named default loses its database row.
|
||||
await project_service.repository.delete(test_project.id)
|
||||
assert await project_service.get_project(config_default) is None
|
||||
|
||||
added_path = str(Path(temp_dir) / "added")
|
||||
os.makedirs(added_path, exist_ok=True)
|
||||
await project_service.add_project(added_name, added_path)
|
||||
|
||||
# The surviving database default wins: config is repointed at it and
|
||||
# the newly added project is not promoted.
|
||||
assert config_manager.default_project == surviving_name
|
||||
db_default = await project_service.repository.get_default_project()
|
||||
assert db_default is not None
|
||||
assert db_default.name == surviving_name
|
||||
added = await project_service.repository.get_by_name(added_name)
|
||||
assert added is not None
|
||||
assert added.is_default is not True
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_add_project_default_parameter_omitted(project_service: ProjectService):
|
||||
"""Test adding a project without set_default parameter defaults to False behavior."""
|
||||
|
||||
Reference in New Issue
Block a user