an.determinism#
The determinism perimeter: what must stay true for a render to be reproducible.
an renders by driving a headless Chromium and screenshotting a WebGL canvas.
Two classes of thing can make that non-reproducible, and they need different
treatment:
Pinned inputs — the rasteriser, the browser build, the encoder. Those are
settings, and they are pinned unconditionally in
an.stage.render (an#31, an#34). Nothing here.
Latent randomness — machinery that is deterministic today by accident.
The vendored PixiJS carries Math.random, Date.now, performance.now and
requestAnimationFrame calls, and NoiseFilter’s default seed is
Math.random(). All of it is dormant because the runtime creates the app with
autoStart: false and drives it with explicit app.render() calls, and
because nothing attaches a filter. Neither fact is written down anywhere that
would go red if it stopped being true. That is what this module watches.
The division of labour is deliberate: runtime.js’s anDeterminismReport
observes and this module judges. So the rule is a pure function of a
plain dict — testable with no browser, no ffmpeg and no render — and changing
the rule is a Python diff rather than a runtime re-stage.
Enforcement is on by default, which is a deliberate deviation from the
issue’s AN_DETERMINISTIC=1 framing and follows the same reasoning an#31
used for the launch flags: a property that only holds when someone remembers to
export a variable is not a property of the system. An assertion nobody runs is
worse than no assertion, because the perimeter reads as guarded. The escape
hatch is the same variable read the other way — AN_DETERMINISTIC=0.
>>> capture_violations({"page": "/index.html", "stage_filter_count": 0,
... "filtered_node_paths": [], "shared_ticker_started": False,
... "auto_start": False})
[]
Module Attributes
Read as an OFF switch, not an on switch — see the module docstring. |
|
The page the capture path must be on. |
Functions
|
Return one sentence per breach of the perimeter; empty means clean. |
Whether to refuse a render whose determinism perimeter has been breached. |
- an.determinism.AN_DETERMINISTIC_ENV_VAR: str = 'AN_DETERMINISTIC'#
Read as an OFF switch, not an on switch — see the module docstring.
- an.determinism.CAPTURE_PAGE: str = 'index.html'#
The page the capture path must be on.
render.pystagespreview.htmlinto every work dir and it carries seven clock calls, so “which page did the browser actually load” is a real question with a wrong answer available.
- an.determinism.capture_violations(report, *, capture_page='index.html')[source]#
Return one sentence per breach of the perimeter; empty means clean.
Each sentence says what was observed, why it makes frames non-reproducible, and what to do about it — because the reader of this message is the person who just added the thing, and “determinism violation” alone tells them nothing.
A missing key is reported rather than defaulted: a report that does not carry a field cannot testify that the field is fine, and silently reading
report.get("shared_ticker_started", False)would turn a stale runtime into a clean bill of health.>>> capture_violations({})[0].startswith("the determinism report is missing") True
- an.determinism.determinism_enforced()[source]#
Whether to refuse a render whose determinism perimeter has been breached.
True unless
AN_DETERMINISTIC_ENV_VARis explicitly falsey.- Return type:
>>> import os >>> os.environ.pop("AN_DETERMINISTIC", None) and None >>> determinism_enforced() True >>> os.environ["AN_DETERMINISTIC"] = "0" >>> determinism_enforced() False >>> del os.environ["AN_DETERMINISTIC"]