MLP214: Serial TeX compile keys the local fork could precompile in parallel¶
qual reports MLP214 when, under a knowledge profile whose
fork-capability overlay declares the submit-all/collect TeX API, at least
4 distinct MathTex / SingleStringMathTex / Tex compile keys are
constructed serially before the scene's first play on a cold cache.
Each distinct cold key blocks on one external TeX compiler + dvisvgm
run; the fork's API submits every formula first and lets the later
constructions join their in-flight jobs (measured on the calibration
machine: 16 distinct cold formulas 120.7 s → 11.7 s,
docs/research/perf-evidence.md — evidence, not a portable constant).
- Default severity:
info - Minimum confidence:
high - Implementation phase:
3 - Required capabilities:
qualified-calls,lifecycle,local-fork-overlay - Fix: none — the DESIGN forbids a generic autofix here; the advice cites
the curated entry points
(
manim.mobject.text.tex_mobject.MathTex.precompile,manim.utils.tex_file_writing.tex_to_svg_file_async) in the explanation
Fork gate (inert under upstream_0_20)¶
The rule reads KnowledgeProfile::tex_parallel_compile(), which is None
for every profile that does not declare the capability — under
upstream_0_20 the rule can never fire, so it never suggests an API the
selected profile does not have (DESIGN 7.3). The declared entry_points
are validated at profile load time to be curated symbols of the resolved
profile.
Counting rules¶
- Distinctness is by compile key, not by construction. The key is the
effective
tex_environmentplus thearg_separator-joined TeX strings (fork defaults:MathTex/SingleStringMathTexjoin with" "intoalign*,Texjoins with""intocenter). Constructing the same formula twice is ONE compile job. - Only literal-provable keys count. Every TeX argument must be a plain
string literal;
arg_separator/tex_environmentmust be literal or absent. An f-string or otherwise dynamic key, a*args/**kwargssplat, or asubstrings_to_isolate/tex_to_color_map/tex_templatekeyword (which change the generated TeX file in ways the rule does not model) makes the construction non-countable — it never contributes to the threshold, and never blocks other keys either (the true distinct-job count can only be higher). - Cold cache only. The resource model starts cold at scene entry
(first render,
CacheAssumption::Cold, DESIGN 5.5). A construction that is not on every path (branch- or loop-dependent,Presence::Maybe) leaves its key's temperature unknown, and unknown is silence — never a counted cold job. Keys constructed after the first play are outside the pre-play prefix and are not counted. On a warm disk cache the advice is moot but harmless: the capability declares that an already-cached key returns an immediately resolved future. - "Before first use" is read from the interpreter's event trace, so
constructions inside inlined helpers count in true program order. The
provable prefix ends at the first play or the first unresolved call
that may itself reach
Scene.play; a scene with summary-derived plays (recursion / depth-cap / unresolvable helper fallbacks) is skipped entirely — a hidden play would break the ordering proof.
One diagnostic is emitted per scene, anchored at the first counted construction; the other distinct keys are attached as related locations, and the evidence lists the counted keys, the curated entry points, the cache assumption, and the first-use boundary.
Interaction with the Cairo fork pipeline¶
When the capability declares in_flight_blocks_cairo_fork, the
explanation adds that every future should be collected before the first
play: in-flight TeX workers force the fork's Cairo fork-per-play pipeline
into serial fallback. This is explanation text, not a separate diagnostic
(the fork-loss causality itself belongs to MLP225's cost report).
Example¶
class Demo(Scene):
def construct(self):
first = MathTex(r"\int_0^1 x^2 \, dx") # MLP214 anchors here
second = MathTex(r"\sum_{n=1}^{\infty} \frac{1}{n^2}")
third = MathTex(r"e^{i\pi} + 1 = 0")
fourth = Tex(r"Euler's identity")
again = MathTex(r"\int_0^1 x^2 \, dx") # duplicate: ONE job
self.play(Write(first), Write(second), Write(third), Write(fourth))
Silent near misses: three distinct keys; duplicate-only batches; keys
built after the first play; f-string keys; a tex_template keyword;
branch-dependent constructions; any profile without the declared
capability.