Bug 3: install() and activate() now verify that declared dependencies
are installed/active before proceeding. Raises ValueError which the
service layer converts to HTTPException 400.
Bug 5: activate() now performs a soft permission check — logs warnings
for declared permissions not found in any discovered plugin.
Bug 2: deactivate() removed routes by path-matching, which caused
routes from other plugins sharing the same prefix (e.g. /api/v1/dms)
to be removed when deactivating one plugin. Now tracks actual route
objects by identity in _mounted_routes and removes only those specific
objects during deactivation.