=== TASK 1 REVIEW PACKAGE (focused) ===
Base for task session: ceaec5d6 (no commit; uncommitted Task 1 changes)
Scope: only score/filename enrichment on search_slices + two new tests.

=== IMPLEMENTATION: search_slices (current) ===
def search_slices(query: str, limit: int = 10) -> list:
    """Call search_knowledge API (get_attachment_link=true). Return normalized hits."""
    if not is_enabled():
        return []
    body = {
        **_collection_ref(),
        "query": query,
        "limit": limit,
        "post_processing": {
            "get_attachment_link": True,
            "rerank_switch": False,
            "chunk_group": True,
            "chunk_diffusion_count": 0,
        },
        "dense_weight": 0.5,
    }
    resp = _request("POST", "/api/knowledge/collection/search_knowledge", body=body)
    points = (resp.get("data") or {}).get("result_list") or (resp.get("data") or {}).get("points") or []
    out = []
    for p in points:
        # search result may wrap the point under different keys
        point = p.get("point") if isinstance(p.get("point"), dict) else p
        norm = _normalize_point(point)
        if not norm.get("point_id"):
            continue
        if not norm.get("doc_id"):
            norm["doc_id"] = (
                point.get("doc_id")
                or (point.get("doc") or {}).get("doc_id")
                or (point.get("doc_info") or {}).get("doc_id")
            )
        # score may live on wrapper or point
        score = p.get("score", p.get("rerank_score"))
        if score is None:
            score = point.get("score", point.get("rerank_score"))
        try:
            norm["score"] = float(score) if score is not None else None
        except (TypeError, ValueError):
            norm["score"] = None

        filename = ""
        if norm.get("doc_id"):
            sc = _read_sidecar(norm["doc_id"]) or {}
            filename = sc.get("filename") or sc.get("title") or ""
        if not filename:
            filename = (
                (point.get("doc_info") or {}).get("doc_name")
                or point.get("doc_name")
                or ""
            )
        norm["filename"] = filename
        out.append(norm)
    return out

=== NEW TESTS ===
    def test_search_slices_includes_score_and_filename(self):
        volcano_kb._write_sidecar("D1", {
            "doc_id": "D1", "filename": "demo.mp4", "status": "ready", "slices": [],
        })
        fake = {"data": {"result_list": [
            {
                "score": 0.3968,
                "point_id": "p1",
                "doc_info": {"doc_id": "D1", "doc_name": "ignored.mp4"},
                "video_start_time": 30000,
                "video_end_time": 60000,
                "description": "电磁流量计",
                "chunk_attachment": [{"info_link": "https://example.com/k.jpg"}],
            },
        ]}}
        with patch.object(volcano_kb, "_request", return_value=fake):
            hits = volcano_kb.search_slices("电磁流量计", limit=5)
        self.assertEqual(hits[0]["score"], 0.3968)
        self.assertEqual(hits[0]["filename"], "demo.mp4")
        self.assertEqual(hits[0]["start_ms"], 30000)
        self.assertEqual(hits[0]["keyframe_url"], "https://example.com/k.jpg")
    def test_search_slices_score_optional(self):
        fake = {"data": {"points": [
            {"point_id": "p2", "doc_id": "D2",
             "system_field": [
                 {"field_name": "video_start_time", "field_value": 0},
                 {"field_name": "video_end_time", "field_value": 1000},
             ],
             "content": "x"},
        ]}}
        with patch.object(volcano_kb, "_request", return_value=fake):
            hits = volcano_kb.search_slices("x", limit=1)
        self.assertIsNone(hits[0].get("score"))

=== IMPLEMENTER CLAIMED DIFF INTENT ===
- After _normalize_point, attach score from wrapper/point (score|rerank_score) as float|None
- Attach filename: sidecar filename/title first, else doc_info.doc_name / doc_name
- _normalize_point unchanged; search_and_download unchanged
