(
profile: Dict[str, Any],
selected_papers: Optional[List[Dict[str, Any]]],
date: Optional[str],
*,
strategy_mode: str,
)
| 636 | |
| 637 | def advance_anchor_recovery( |
| 638 | profile: Dict[str, Any], |
| 639 | selected_papers: Optional[List[Dict[str, Any]]], |
| 640 | date: Optional[str], |
| 641 | *, |
| 642 | strategy_mode: str, |
| 643 | ) -> Tuple[Dict[str, Any], Optional[Dict[str, Any]]]: |
| 644 | updated = copy.deepcopy(profile) |
| 645 | drift_state = _ensure_anchor_state(updated) |
| 646 | status = str(drift_state.get("status") or "stable") |
| 647 | if status not in {"shifting", "recovered"}: |
| 648 | return updated, None |
| 649 | if int(drift_state.get("commitment_days_remaining", 0) or 0) > 0: |
| 650 | return updated, None |
| 651 | |
| 652 | selected_papers = list(selected_papers or []) |
| 653 | if not selected_papers: |
| 654 | return updated, None |
| 655 | |
| 656 | anchor_topic = str(drift_state.get("anchor_topic") or "").strip() |
| 657 | if not anchor_topic: |
| 658 | return updated, None |
| 659 | |
| 660 | baseline_topics = [ |
| 661 | topic for topic in (drift_state.get("baseline_core_directions", {}) or {}).keys() |
| 662 | if str(topic).strip() and str(topic).strip() != anchor_topic |
| 663 | ] |
| 664 | total_count = len(selected_papers) |
| 665 | anchor_hits = sum(1 for paper in selected_papers if _paper_matches_any_topic(paper, [anchor_topic])) |
| 666 | baseline_hits = sum(1 for paper in selected_papers if _paper_matches_any_topic(paper, baseline_topics)) |
| 667 | anchor_ratio = anchor_hits / max(1, total_count) |
| 668 | baseline_ratio = baseline_hits / max(1, total_count) |
| 669 | |
| 670 | recovery_mode: Optional[str] = None |
| 671 | if anchor_hits >= 2 and baseline_hits == 0: |
| 672 | recovery_mode = "consolidate_new" |
| 673 | elif anchor_hits >= 1 and baseline_hits >= 1: |
| 674 | recovery_mode = "rebalance" |
| 675 | elif baseline_hits >= 2: |
| 676 | recovery_mode = "rollback" |
| 677 | |
| 678 | if recovery_mode is None: |
| 679 | return updated, None |
| 680 | |
| 681 | baseline_core = _normalize_weight_map(copy.deepcopy(drift_state.get("baseline_core_directions", {}) or {})) |
| 682 | core_directions = _normalize_weight_map(copy.deepcopy(updated.get("core_directions", {}) or {})) |
| 683 | topic_weights = _normalize_weight_map(copy.deepcopy(updated.get("topic_weights", {}) or core_directions)) |
| 684 | |
| 685 | if recovery_mode == "rebalance": |
| 686 | for topic, weight in baseline_core.items(): |
| 687 | if topic == anchor_topic: |
| 688 | continue |
| 689 | core_directions[topic] = max(float(core_directions.get(topic, 0.0) or 0.0), round(min(1.0, weight * 0.85), 4)) |
| 690 | elif recovery_mode == "rollback": |
| 691 | for topic, weight in baseline_core.items(): |
| 692 | if topic == anchor_topic: |
| 693 | continue |
| 694 | core_directions[topic] = max(float(core_directions.get(topic, 0.0) or 0.0), round(min(1.0, weight), 4)) |
| 695 | if anchor_topic in core_directions: |
no test coverage detected