from pathlib import Path
p=Path('/opt/struktur/social-media-agent/app.py')
s=p.read_text()
# Add source platform/type to the API select.
s=s.replace(' "SELECT signal_id, signal_category, radar_score, topic, extracted_hook,"\n', ' "SELECT signal_id, signal_category, source_type, source_platform, radar_score, topic, extracted_hook,"\n', 1)
# Replace status/competition/sort setup with explicit platform filters and real sort semantics.
old=''' comp_clause = "AND competition_signal = 1" if competition_only else ""\n\n sort_map = {\n "op_priority": "pinned DESC, operational_priority DESC, radar_score DESC",\n "relevance": "pinned DESC, radar_score DESC",\n "newest": "pinned DESC, created_at DESC",\n "virality": "pinned DESC, virality_level DESC, radar_score DESC",\n "emotionality": "pinned DESC, emotionality_level DESC, radar_score DESC",\n "linkedin": "pinned DESC, platform_linkedin DESC, radar_score DESC",\n "facebook": "pinned DESC, platform_facebook DESC, radar_score DESC",\n "tiktok": "pinned DESC, platform_tiktok DESC, radar_score DESC",\n }\n order_by = sort_map.get(sort, "pinned DESC, operational_priority DESC, radar_score DESC")\n'''
new=''' comp_clause = "AND competition_signal = 1" if competition_only else ""\n\n # source_platform is the canonical read-time field; old rows with an\n # empty value remain classifiable through source_type. LI/FB are real\n # source filters, not merely sort orders.\n platform_expr = "lower(COALESCE(NULLIF(source_platform,''), source_type))"\n if sort == "facebook":\n platform_clause = (\n "AND (" + platform_expr + " IN ('facebook','meta','meta_ad') "\n "OR source_type IN ('facebook_public','meta_ad'))"\n )\n elif sort == "linkedin":\n platform_clause = (\n "AND (" + platform_expr + " = 'linkedin' "\n "OR source_type = 'linkedin')"\n )\n else:\n platform_clause = ""\n\n sort_map = {\n "op_priority": "pinned DESC, operational_priority DESC, radar_score DESC, observed_at DESC",\n "relevance": "pinned DESC, radar_score DESC, relevance_score DESC, observed_at DESC",\n "newest": "pinned DESC, COALESCE(observed_at, created_at, timestamp) DESC, radar_score DESC",\n "virality": "pinned DESC, virality_level DESC, radar_score DESC, observed_at DESC",\n "emotionality": "pinned DESC, emotionality_level DESC, radar_score DESC, observed_at DESC",\n "linkedin": "pinned DESC, radar_score DESC, observed_at DESC",\n "facebook": "pinned DESC, radar_score DESC, observed_at DESC",\n "tiktok": "pinned DESC, platform_tiktok DESC, radar_score DESC",\n }\n order_by = sort_map.get(sort, "pinned DESC, operational_priority DESC, radar_score DESC, observed_at DESC")\n'''
if old not in s: raise SystemExit('filter setup anchor not found')
s=s.replace(old,new,1)
# Highlight must remain explicit; normal platform filter must be bypassed only for explicit deep links.
s=s.replace(''' st_clause = ""\n st_params = []\n comp_clause = ""\n''',''' st_clause = ""\n st_params = []\n comp_clause = ""\n platform_clause = ""\n''',1)
s=s.replace(''' f" {st_clause} {comp_clause}"\n''',''' f" {st_clause} {comp_clause} {platform_clause}"\n''',1)
p.write_text(s)
p=Path('/opt/struktur/social-media-agent/templates/cockpit.html')
s=p.read_text()
# Backend order must be preserved inside category groups; sorting here erased every button's effect.
s=s.replace(" {% set cat_sigs = cat_grp|sort(attribute='radar_score', reverse=True) %}\n", " {% set cat_sigs = cat_grp %}\n", 1)
# Make source/platform immediately visible on every card.
s=s.replace(".stag{", ".source-badge{display:inline-flex;align-items:center;padding:2px 5px;border-radius:3px;background:rgba(79,142,247,.15);color:#93c5fd;font-size:9px;font-weight:800;letter-spacing:.04em;margin-right:5px;} .stag{")
old=""" <span class=\"stag\" title=\"{{s.source_name}}\">{{s.source_name or '—'}}</span>\n"""
new=""" <span class=\"source-badge\">{{(s.source_platform or s.source_type or 'source')|replace('_',' ')|upper}}</span><span class=\"stag\" title=\"{{s.source_name}}\">{{s.source_name or '—'}}</span>\n"""
if old not in s: raise SystemExit('badge anchor not found')
s=s.replace(old,new,1)
p.write_text(s)