66name/title a stable identity. This layer runs *after* Core stream presentation so
77it never destroys provider-returned quality/language/codec facts before they are
88normalized.
9+
10+ Every currently published provider must exist in ``assets/providers/emojis.json``
11+ (the repository contract checks exact 92/92 coverage). A provider discovered only
12+ inside a future/synthetic Core probe may still pass safely with a generic alphabet
13+ emoji and a readable name derived from its id; it is not publishable until the
14+ committed inventory is updated.
915"""
1016from __future__ import annotations
1117
1218import hashlib
1319import json
20+ import re
1421from pathlib import Path
1522from typing import Any
1623
1724MARKER = "NUVIO_GLOBAL_PROVIDER_BRANDING_V1"
1825ROOT = Path (__file__ ).resolve ().parents [2 ]
1926BRANDING = ROOT / "assets" / "providers" / "emojis.json"
27+ FALLBACK_EMOJI = "🔤"
28+
29+
30+ def _fallback_name (provider_id : str ) -> str :
31+ parts = [part for part in re .split (r"[-_\s]+" , str (provider_id or "" ).strip ()) if part ]
32+ return " " .join (part [:1 ].upper () + part [1 :] for part in parts ) or "Source"
2033
2134
2235def _load_provider (provider_id : str ) -> dict [str , str ]:
@@ -26,9 +39,10 @@ def _load_provider(provider_id: str) -> dict[str, str]:
2639 providers = payload .get ("providers" )
2740 if not isinstance (providers , dict ):
2841 raise ValueError ("provider emoji map providers must be an object" )
29- row = providers .get (str (provider_id or "" ).strip ().casefold ())
42+ normalized_id = str (provider_id or "" ).strip ().casefold ()
43+ row = providers .get (normalized_id )
3044 if not isinstance (row , dict ):
31- raise ValueError ( f"provider emoji map is missing { provider_id } " )
45+ return { "name" : _fallback_name ( normalized_id ), " emoji" : FALLBACK_EMOJI }
3246 name = str (row .get ("name" ) or "" ).strip ()
3347 emoji = str (row .get ("emoji" ) or "" ).strip ()
3448 if not name or not emoji :
@@ -52,20 +66,13 @@ def apply(text: str, options: dict[str, Any] | None = None, **kwargs: Any) -> st
5266 provider_id = str (context .get ("provider_id" ) or "" ).strip ().casefold ()
5367 if not provider_id :
5468 return text
55- try :
56- row = _load_provider (provider_id )
57- except ValueError :
58- # Synthetic Core fixtures are not published providers. Real provider
59- # coverage is fail-closed by the committed branding inventory contract.
60- if provider_id .startswith ("synthetic-" ):
61- return text
62- raise
69+ row = _load_provider (provider_id )
6370
6471 payload = {
6572 "providerId" : provider_id ,
6673 "providerName" : row ["name" ],
6774 "providerEmoji" : row ["emoji" ],
68- "implementationRevision" : "post-presentation-emoji-stream-label-v2 " ,
75+ "implementationRevision" : "post-presentation-emoji-stream-label-v3 " ,
6976 }
7077 serialized = json .dumps (payload , ensure_ascii = False , separators = ("," , ":" ))
7178 marker = f"{ MARKER } :{ hashlib .sha256 (serialized .encode ('utf-8' )).hexdigest ()[:12 ]} "
0 commit comments