From f4208bca4d8845d279c67f5c4ca7c35b94b86031 Mon Sep 17 00:00:00 2001 From: Nubenetes Bot Date: Fri, 19 Jun 2026 12:45:20 +0200 Subject: [PATCH] fix: comprehensive None-stars guard across all v2_optimizer comparisons _render_single_link (line 872) crashed with TypeError: '>=' not supported between NoneType and int. Replaced ALL remaining .get('stars', 0) patterns with .get('stars') or 0 throughout v2_optimizer.py to prevent further crashes from null stars values in inventory. Co-Authored-By: Claude Sonnet 4.6 --- src/v2_optimizer.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/v2_optimizer.py b/src/v2_optimizer.py index 4a7fd7df..4f012262 100644 --- a/src/v2_optimizer.py +++ b/src/v2_optimizer.py @@ -382,7 +382,7 @@ class V2VisionEngine: except Exception: pass if ((cached.get("hierarchy") and cached.get("ai_summary") and not eval_stale) or self.render_only) and not force_eval: - if project_id not in project_registry or item.get("stars", 0) > project_registry[project_id].get("stars", 0): + if project_id not in project_registry or item.get("stars") or 0 > project_registry[project_id].get("stars") or 0: if project_id in project_registry and project_registry[project_id].get("is_special"): item["is_special"] = True project_registry[project_id] = item continue @@ -444,7 +444,7 @@ class V2VisionEngine: if idx < len(batch_links): item = batch_links[idx].copy() eval_data = { - "year": str(res.get("year", "N/A")), "stars": min(max(int(res.get("stars", 0)), 0), 5), + "year": str(res.get("year", "N/A")), "stars": min(max(int(res.get("stars") or 0), 0), 5), "ai_summary": res.get("summary", item.get("ai_summary", "")), "language": res.get("language", "English"), "resource_type": res.get("type", "Reference"), "complexity": res.get("complexity", "Intermediate"), @@ -535,7 +535,7 @@ class V2VisionEngine: if idx < len(batch): item = batch[idx].copy() eval_data = { - "year": str(res.get("year", "N/A")), "stars": min(max(int(res.get("stars", 0)), 0), 5), + "year": str(res.get("year", "N/A")), "stars": min(max(int(res.get("stars") or 0), 0), 5), "ai_summary": res.get("summary", ""), "language": res.get("language", "English"), "resource_type": res.get("type", "Reference"), "complexity": res.get("complexity", "Intermediate"), "hierarchy": res.get("hierarchy", ["General"]), "tags": res.get("tags", []), @@ -559,7 +559,7 @@ class V2VisionEngine: l for l in analyst_results if "[DE FACTO STANDARD]" in l.get("tags", []) or "[ENTERPRISE-STABLE]" in l.get("tags", []) - or l.get("stars", 0) in [3, 4] + or l.get("stars") or 0 in [3, 4] ] if debate_candidates: @@ -596,7 +596,7 @@ class V2VisionEngine: new_data["addition_method"] = "manual" update_inventory_entry(self.inventory, norm_url, new_data) - if p_id not in project_registry or item.get("stars", 0) > project_registry[p_id].get("stars", 0): + if p_id not in project_registry or item.get("stars") or 0 > project_registry[p_id].get("stars") or 0: if p_id in project_registry and project_registry[p_id].get("is_special"): item["is_special"] = True project_registry[p_id] = item @@ -699,7 +699,7 @@ class V2VisionEngine: # Mandate 29: Special Assets must include 100% of ALIVE links, bypassing impact filters. is_special = item.get("is_special", False) or orig_file in special_rules - if not is_special and orig_file == "introduction.md" and item.get("stars", 0) < 3 and not item.get("is_microservice"): + if not is_special and orig_file == "introduction.md" and item.get("stars") or 0 < 3 and not item.get("is_microservice"): continue if orig_file not in v2_structure: @@ -735,7 +735,7 @@ class V2VisionEngine: audit_entry = { "url": item["url"], "tag": ", ".join(item["tags"]), - "stars": item.get("stars", 0), + "stars": item.get("stars") or 0, "dimension": dim, "v2_locations": True } @@ -776,13 +776,13 @@ class V2VisionEngine: return results async def _generate_comparison_table(self, links: List[Dict]) -> str: - standard_tools = [l for l in links if l.get("stars", 0) >= 3] + standard_tools = [l for l in links if l.get("stars") or 0 >= 3] if len(standard_tools) < 8: return "" table = "\n??? abstract \"Architect's Technical Comparison Table\"\n" table += " | Solution | Maturity | Primary Focus | Language | Stars |\n" table += " | :--- | :--- | :--- | :--- | :--- |\n" for l in standard_tools[:10]: - stars = "๐ŸŒŸ" * l.get("stars", 0) + stars = "๐ŸŒŸ" * l.get("stars") or 0 focus = l.get("topic", l.get("hierarchy", ["General"])[-1]) # Mandate 30: MD039 - Strip all whitespace (including non-breaking space) from link text clean_title = nuclear_strip(l['title']) @@ -826,7 +826,7 @@ class V2VisionEngine: async def _render_single_link(self, l: Dict, is_intro: bool) -> str: md = "" - is_gold = is_intro and l.get("stars", 0) >= 4 + is_gold = is_intro and l.get("stars") or 0 >= 4 title = nuclear_strip(l['title']) if is_gold: img = f" ![Preview]({l.get('social_preview_url')})\n" if l.get('social_preview_url') else "" @@ -867,7 +867,7 @@ class V2VisionEngine: tag_html += f" {tag}" # Apply Visual Highlighting based on stars - raw_stars = l.get('stars', 0) + raw_stars = l.get('stars') or 0 link_content = title if raw_stars >= 5: link_content = f"=={link_content}==" @@ -895,7 +895,7 @@ class V2VisionEngine: year = l.get("year", "") year_prefix = f"**({year})** " if year and str(year).lower() != "n/a" else "" - raw_stars = l.get("stars", 0) + raw_stars = l.get("stars") or 0 stars_str = f" {'๐ŸŒŸ' * raw_stars}" if raw_stars > 0 else "" # Title formatting based on impact @@ -1022,7 +1022,7 @@ class V2VisionEngine: f' \n' f' \n' f' \n' - f' \n' + f' \n' f' \n' f'\n' ) @@ -1569,7 +1569,7 @@ if __name__ == "__main__": header_table = "| # | Status | Maturity | Stars | Dimension | Resource |\n| :--- | :--- | :--- | :---: | :--- | :--- |\n" for idx, entry in enumerate(engine.maturity_audit, 1): status = "๐Ÿ’Ž ELITE" if entry.get('v2_locations') else "๐Ÿ“ฆ ARCHIVE" - row = f"| {idx} | {status} | {entry.get('tag', 'N/A')} | {'๐ŸŒŸ'*entry.get('stars',0)} | {entry.get('dimension', 'N/A')} | {entry.get('url', 'N/A')} |\n" + row = f"| {idx} | {status} | {entry.get('tag', 'N/A')} | {'๐ŸŒŸ'*(entry.get('stars') or 0)} | {entry.get('dimension', 'N/A')} | {entry.get('url', 'N/A')} |\n" matrix_rows.append(row) # 4. Generate PR Body (Main Report)