@@ -124,11 +124,15 @@ def md_escape(text: str) -> str:
124124 return str (text ).replace ("|" , "\\ |" )
125125
126126
127+ # Preferred README ordering, not an allow-list. Modalities not listed here are
128+ # appended deterministically so future backends cannot be silently omitted.
127129MODALITY_ORDER = [
128130 "Text generation" ,
129131 "Speech-to-text" ,
130132 "Text-to-speech" ,
133+ "Audio generation" ,
131134 "Image generation" ,
135+ "3D generation" ,
132136]
133137OS_LABEL = {"windows" : "Windows" , "linux" : "Linux" , "macos" : "macOS" }
134138OS_ORDER = ["windows" , "linux" , "macos" ]
@@ -150,17 +154,31 @@ def _ordered(recipes: dict) -> list:
150154 return sorted (recipes .items (), key = lambda kv : kv [1 ].get ("order" , 999 ))
151155
152156
157+ def _ordered_modalities (by_mod : dict [str , list ]) -> list [str ]:
158+ """Return known modalities first, then future modalities deterministically."""
159+ preferred = [mod for mod in MODALITY_ORDER if mod in by_mod ]
160+ additional = sorted (set (by_mod ) - set (MODALITY_ORDER ))
161+ return preferred + additional
162+
163+
153164def render_readme_matrix (recipes : dict ) -> str :
154165 # Group descriptor-backed recipes by modality, in descriptor registry order.
155- by_mod : dict [str , list ] = {m : [] for m in MODALITY_ORDER }
166+ # MODALITY_ORDER controls presentation only; it must never filter recipes.
167+ by_mod : dict [str , list ] = {}
156168 for recipe , info in _ordered (recipes ):
157- mod = info .get ("modality" )
158- if not mod or mod not in by_mod :
169+ support_rows = info .get ("support" , [] )
170+ if not support_rows :
159171 continue
172+ mod = info .get ("modality" )
173+ if not mod :
174+ sys .exit (
175+ f"Backend '{ recipe } ' has support rows but no documentation modality"
176+ )
177+
160178 # Merge support rows sharing a (backend, device summary); union their OS.
161179 merged : list [dict ] = []
162180 seen : dict [tuple , dict ] = {}
163- for row in info . get ( "support" , []) :
181+ for row in support_rows :
164182 key = (row ["backend" ], row .get ("device_summary" , "" ))
165183 if key in seen :
166184 seen [key ]["os" ] |= set (row .get ("os" , []))
@@ -173,7 +191,7 @@ def render_readme_matrix(recipes: dict) -> str:
173191 seen [key ] = d
174192 merged .append (d )
175193 if merged :
176- by_mod [ mod ] .append ((recipe , info , merged ))
194+ by_mod . setdefault ( mod , []) .append ((recipe , info , merged ))
177195
178196 out = [
179197 "<table>" ,
@@ -188,11 +206,9 @@ def render_readme_matrix(recipes: dict) -> str:
188206 " </thead>" ,
189207 " <tbody>" ,
190208 ]
191- for mod in MODALITY_ORDER :
209+ for mod in _ordered_modalities ( by_mod ) :
192210 recipes_in = by_mod [mod ]
193- if not recipes_in :
194- continue
195- mod_span = sum (len (m ) for _ , _ , m in recipes_in )
211+ mod_span = sum (len (merged ) for _ , _ , merged in recipes_in )
196212 first_mod = True
197213 for recipe , info , merged in recipes_in :
198214 engine = f"<code>{ recipe } </code>" + (
0 commit comments