tag conventions
This commit is contained in:
@@ -9,6 +9,7 @@ x-personal-mcp:
|
|||||||
- uv
|
- uv
|
||||||
- uvicorn
|
- uvicorn
|
||||||
- docker
|
- docker
|
||||||
|
- architecture
|
||||||
capabilities:
|
capabilities:
|
||||||
- resource://skills/fastapi-uv-docker/document
|
- 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