@@ -1640,6 +1640,83 @@ async def fake_get_active_project(client, project_name, context=None, headers=No
16401640 assert permalink_context .workspace_slug == "team-paul"
16411641 assert permalink_context .workspace_type == "organization"
16421642
1643+ @pytest .mark .asyncio
1644+ async def test_cloud_project_workspace_id_uses_workspace_provider_for_permalink_context (
1645+ self , config_manager , monkeypatch
1646+ ):
1647+ """Injected workspace metadata supplies slug/type without project index discovery."""
1648+ from contextlib import asynccontextmanager
1649+
1650+ import basic_memory .mcp .project_context as project_context
1651+ from basic_memory .mcp .project_context import get_project_client
1652+ from basic_memory .config import ProjectEntry , ProjectMode
1653+ from basic_memory .schemas .project_info import ProjectItem
1654+ from basic_memory .workspace_context import (
1655+ WorkspacePermalinkContext ,
1656+ current_workspace_permalink_context ,
1657+ )
1658+
1659+ config = config_manager .load_config ()
1660+ config .projects ["cloud-proj" ] = ProjectEntry (
1661+ path = str (config_manager .config_dir .parent / "cloud-proj" ),
1662+ mode = ProjectMode .CLOUD ,
1663+ workspace_id = "per-project-tenant-id" ,
1664+ )
1665+ config .cloud_api_key = "bmc_test123"
1666+ config_manager .save_config (config )
1667+
1668+ workspace = _workspace (
1669+ tenant_id = "per-project-tenant-id" ,
1670+ workspace_type = "organization" ,
1671+ slug = "team-paul" ,
1672+ name = "Team Paul" ,
1673+ role = "editor" ,
1674+ )
1675+
1676+ async def fake_workspace_provider ():
1677+ return [workspace ]
1678+
1679+ async def fail_ensure_workspace_project_index (context = None ): # pragma: no cover
1680+ raise AssertionError ("Configured workspace_id should not require project discovery" )
1681+
1682+ monkeypatch .setattr (project_context , "_workspace_provider" , fake_workspace_provider )
1683+ monkeypatch .setattr (
1684+ project_context ,
1685+ "_ensure_workspace_project_index" ,
1686+ fail_ensure_workspace_project_index ,
1687+ )
1688+
1689+ seen : dict [str , object ] = {}
1690+
1691+ @asynccontextmanager
1692+ async def fake_get_client (project_name = None , workspace = None ):
1693+ seen ["project_name" ] = project_name
1694+ seen ["workspace" ] = workspace
1695+ seen ["permalink_context" ] = current_workspace_permalink_context ()
1696+ yield object ()
1697+
1698+ async def fake_get_active_project (client , project_name , context = None , headers = None ):
1699+ return ProjectItem (
1700+ id = 1 ,
1701+ external_id = "cloud-project-id" ,
1702+ name = project_name ,
1703+ path = "/cloud-proj" ,
1704+ is_default = False ,
1705+ )
1706+
1707+ monkeypatch .setattr ("basic_memory.mcp.async_client.get_client" , fake_get_client )
1708+ monkeypatch .setattr (project_context , "get_active_project" , fake_get_active_project )
1709+
1710+ async with get_project_client (project = "cloud-proj" ) as (_client , active_project ):
1711+ assert active_project .external_id == "cloud-project-id"
1712+
1713+ assert seen ["project_name" ] == "cloud-proj"
1714+ assert seen ["workspace" ] == "per-project-tenant-id"
1715+ permalink_context = cast (WorkspacePermalinkContext | None , seen ["permalink_context" ])
1716+ assert permalink_context is not None
1717+ assert permalink_context .workspace_slug == "team-paul"
1718+ assert permalink_context .workspace_type == "organization"
1719+
16431720 @pytest .mark .asyncio
16441721 async def test_cloud_project_workspace_id_routes_without_discovery (
16451722 self , config_manager , monkeypatch
0 commit comments