feat(km): add full corpus asset taxonomy readback
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 1s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / build-and-deploy (push) Has been cancelled
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / tests (push) Has been cancelled

This commit is contained in:
Your Name
2026-07-03 16:12:48 +08:00
parent 37dda358a3
commit f99305e481
10 changed files with 312 additions and 17 deletions

View File

@@ -8,7 +8,11 @@ from sqlalchemy.dialects import postgresql
from src.db.models import KnowledgeEntryRecord
from src.models.knowledge import EntrySource, EntryStatus, EntryType
from src.repositories.knowledge_repository import KnowledgeDBRepository, _enum_text
from src.repositories.knowledge_repository import (
KnowledgeDBRepository,
_ASSET_TAXONOMY_KEYS,
_enum_text,
)
def _record(**overrides):
@@ -177,6 +181,33 @@ async def test_get_categories_normalizes_null_or_blank_category() -> None:
assert "coalesce(nullif(trim(knowledge_entries.category)" in compiled
@pytest.mark.asyncio
async def test_get_asset_taxonomy_counts_uses_stable_ai_automation_lenses() -> None:
class _TaxonomyDb:
def __init__(self):
self.statements = []
self.values = list(range(10, 10 + len(_ASSET_TAXONOMY_KEYS)))
async def execute(self, statement):
self.statements.append(statement)
return _ScalarResult(self.values.pop(0))
db = _TaxonomyDb()
repo = KnowledgeDBRepository(db=db) # type: ignore[arg-type]
counts = await repo.get_asset_taxonomy_counts()
assert [key for key, _ in counts] == list(_ASSET_TAXONOMY_KEYS)
assert [count for _, count in counts] == list(range(10, 10 + len(_ASSET_TAXONOMY_KEYS)))
compiled = "\n".join(
str(stmt.compile(dialect=postgresql.dialect(), compile_kwargs={"literal_binds": True}))
for stmt in db.statements
).lower()
assert "source_control" in compiled
assert "awoooi" in compiled
assert "related_playbook_id is not null" in compiled
def test_enum_text_helper_casts_status_to_lowercase_text() -> None:
compiled = str(
(_enum_text(KnowledgeEntryRecord.status) == EntryStatus.ARCHIVED.value).compile(

View File

@@ -41,6 +41,21 @@ async def test_knowledge_list_entries_fails_soft_when_readback_breaks(monkeypatc
"general",
]
assert all(row.count == 0 for row in response.categories)
assert [row.key for row in response.asset_taxonomy] == [
"project",
"product",
"website",
"service",
"package",
"tool",
"log",
"alert",
"playbook",
"rag",
"mcp",
"schedule",
]
assert all(row.count == 0 for row in response.asset_taxonomy)
assert response.readback_status == "degraded"
assert response.operator_stage == "knowledge_readback_degraded_ai_controlled_repair"
assert response.next_step == "queue_ai_controlled_km_readback_retry_tagging_and_connector_verifier"
@@ -75,3 +90,31 @@ async def test_knowledge_categories_fails_soft_when_readback_breaks(monkeypatch)
"general",
]
assert all(row.count == 0 for row in categories)
@pytest.mark.asyncio
async def test_knowledge_asset_taxonomy_fails_soft_when_readback_breaks(monkeypatch) -> None:
monkeypatch.setattr(
knowledge_service_module,
"get_db_context",
lambda: _BrokenDbContext(),
)
service = KnowledgeService.__new__(KnowledgeService)
taxonomy = await service.get_asset_taxonomy()
assert [row.key for row in taxonomy] == [
"project",
"product",
"website",
"service",
"package",
"tool",
"log",
"alert",
"playbook",
"rag",
"mcp",
"schedule",
]
assert all(row.count == 0 for row in taxonomy)