tag conventions
This commit is contained in:
@@ -9,6 +9,7 @@ x-personal-mcp:
|
||||
- uv
|
||||
- uvicorn
|
||||
- docker
|
||||
- architecture
|
||||
capabilities:
|
||||
- resource://skills/fastapi-uv-docker/document
|
||||
---
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from personal_mcp.registry.load import load_docs_registry
|
||||
|
||||
pytestmark = pytest.mark.unit
|
||||
|
||||
REGISTRY = load_docs_registry(
|
||||
package_anchor="personal_mcp",
|
||||
docs_root="../../docs",
|
||||
)
|
||||
|
||||
# Convention: every skill should include tags for the core libraries/frameworks
|
||||
# it relies on so search_patterns query terms map to discoverable skills.
|
||||
REQUIRED_LIBRARY_TAGS_BY_SKILL = {
|
||||
"copilot-customization": {"copilot", "vscode", "mcp"},
|
||||
"fastapi-async-sqlalchemy-modernization": {"fastapi", "sqlalchemy", "asyncio"},
|
||||
"fastapi-uv-docker": {"fastapi", "uv", "uvicorn", "docker"},
|
||||
"mcp-details": {"mcp", "fastmcp"},
|
||||
"new-skill": {"mcp", "fastmcp"},
|
||||
"nicegui": {"nicegui", "fastapi"},
|
||||
"nicegui-ui-customization": {"nicegui", "fastapi"},
|
||||
"pytest-scaffolding": {"pytest", "testing", "fastapi", "asyncio", "anyio"},
|
||||
"python-logging-dictconfig": {"python", "logging"},
|
||||
"python-typing": {"python", "typing"},
|
||||
"ruff-linting-formating": {"ruff", "python"},
|
||||
"vscode-configuration": {"vscode", "debugpy", "fastapi", "python"},
|
||||
"zensical-docs": {"zensical", "mkdocs", "mkdocs-material", "mkdocstrings"},
|
||||
}
|
||||
|
||||
LIBRARY_OR_PLATFORM_TAGS = {
|
||||
"anyio",
|
||||
"asyncio",
|
||||
"copilot",
|
||||
"debugpy",
|
||||
"docker",
|
||||
"fastapi",
|
||||
"fastmcp",
|
||||
"logging",
|
||||
"mcp",
|
||||
"mkdocs",
|
||||
"mkdocs-material",
|
||||
"mkdocstrings",
|
||||
"nicegui",
|
||||
"pytest",
|
||||
"python",
|
||||
"ruff",
|
||||
"sqlalchemy",
|
||||
"typing",
|
||||
"uv",
|
||||
"uvicorn",
|
||||
"vscode",
|
||||
"zensical",
|
||||
}
|
||||
|
||||
DOMAIN_FACET_TAGS = {
|
||||
"agent-skills",
|
||||
"architecture",
|
||||
"authoring",
|
||||
"bootstrap",
|
||||
"ci",
|
||||
"custom-agents",
|
||||
"customization",
|
||||
"deterministic",
|
||||
"discovery",
|
||||
"docs",
|
||||
"documentation",
|
||||
"formatting",
|
||||
"frontend",
|
||||
"hooks",
|
||||
"information-architecture",
|
||||
"instructions",
|
||||
"launch-json",
|
||||
"linting",
|
||||
"modernization",
|
||||
"observability",
|
||||
"personal-mcp",
|
||||
"prompts",
|
||||
"references",
|
||||
"scaffolding",
|
||||
"skills",
|
||||
"source-docs",
|
||||
"static-analysis",
|
||||
"tasks-json",
|
||||
"testing",
|
||||
"type-hints",
|
||||
"ui",
|
||||
}
|
||||
|
||||
TAG_CONVENTION_PARAMETERS = tuple(
|
||||
pytest.param(skill_id, required_tags, id=skill_id)
|
||||
for skill_id, required_tags in sorted(REQUIRED_LIBRARY_TAGS_BY_SKILL.items())
|
||||
)
|
||||
|
||||
SKILL_IDS = tuple(pytest.param(skill_id, id=skill_id) for skill_id in sorted(REGISTRY.skills_by_id))
|
||||
|
||||
|
||||
class TestSkillTagConventions:
|
||||
"""Covers tag taxonomy conventions for skill discoverability."""
|
||||
|
||||
class TestRequiredLibraryTags:
|
||||
"""Covers required per-skill library and framework tags."""
|
||||
|
||||
@pytest.mark.parametrize(("skill_id", "required_tags"), TAG_CONVENTION_PARAMETERS)
|
||||
def test_includes_required_library_and_framework_tags(
|
||||
self,
|
||||
skill_id: str,
|
||||
required_tags: set[str],
|
||||
) -> None:
|
||||
"""Ensures each skill includes its required library/framework tags."""
|
||||
skill = REGISTRY.skills_by_id[skill_id]
|
||||
skill_tags = set(skill.tags)
|
||||
|
||||
assert required_tags.issubset(skill_tags)
|
||||
|
||||
class TestTagTaxonomyShape:
|
||||
"""Covers baseline tag-shape guarantees across all skills."""
|
||||
|
||||
@pytest.mark.parametrize("skill_id", SKILL_IDS)
|
||||
def test_includes_library_or_platform_tag(self, skill_id: str) -> None:
|
||||
"""Ensures each skill includes at least one library/platform tag."""
|
||||
skill = REGISTRY.skills_by_id[skill_id]
|
||||
skill_tags = set(skill.tags)
|
||||
|
||||
assert skill_tags & LIBRARY_OR_PLATFORM_TAGS
|
||||
|
||||
@pytest.mark.parametrize("skill_id", SKILL_IDS)
|
||||
def test_includes_domain_facet_tag(self, skill_id: str) -> None:
|
||||
"""Ensures each skill includes at least one domain facet tag."""
|
||||
skill = REGISTRY.skills_by_id[skill_id]
|
||||
skill_tags = set(skill.tags)
|
||||
|
||||
assert skill_tags & DOMAIN_FACET_TAGS
|
||||
Reference in New Issue
Block a user