Orchestrata Ultimate › Gates › ast (AST refresh)

Gate: __ast__ (AST refresh)

At a glance

Purpose Refuse to evaluate any battery gate against a stale plans/ast-ultimate.json, and refuse a refresh that leaves runtime_calls empty.
Where it runs The scripts/gates.py battery only, as the automatic pre-step of main().
Trigger Every python scripts/gates.py run whose src/ tests/ scripts/ fingerprint differs from the cached __ast__ entry (always under --all); skipped with --no-fix-ast.
Exact command uv run ast-sync, then python scripts/build_runtime_callgraph.py reaugment, then a runtime_calls count check (refresh_ast(), read through the AST toolkit).
Blocks A failed step or a zero runtime_calls count prints [gates] FAIL ast-refresh … and the battery returns 1 before any gate runs.
Ruling / ADR None names the pre-step. The session-time snapshot path is ADR-0097.
Last recorded verdict ok: true under __ast__ in the primary checkout's .cache/gates.json (file last written 2026-09-22 10:01 local). wt-MAP-PRECOMMIT has no .cache/gates.json.

Diagram projects-orchestrata-ultimate-gates-ast-refresh-1

__ast__ is the one registry name in .cache/gates.json that is not an entry in the GATES dict — it is the automatic pre-step scripts/gates.py::main() runs before any gate, and it is cached and verdict-tracked exactly like the others. It is listed here because the brief's registry census counts 24 cached names, and this is the 24th.

What it refuses

Running the battery against a stale plans/ast-ultimate.json snapshot — and, just as important, refusing any refresh that silently destroys the runtime call graph the RTM depends on.

Why it exists

From scripts/gates.py's module docstring (self-healing behavior #3):

"AST staleness: plans/ast-ultimate.json goes stale on every source change, and uv run ast-sync ZEROES runtime_calls unless build_runtime_callgraph.py reaugment runs after it. That two-step ordering was documented and still forgotten repeatedly; --fix-ast does both, in order, and verifies the augmentation landed."

And from refresh_ast()'s own docstring:

"Both steps, in this order, always. ast-sync rebuilds plans/ast-ultimate.json from source and drops every runtime_calls entry; build_runtime_callgraph.py reaugment puts them back from the recorded runtime capture. Running the first without the second silently destroys the runtime call graph the RTM depends on — measured twice, and the reason this is one function rather than two commands to remember."

Staleness is called "the single most frequent gate failure" in the same file, and the refresh runs before the gates "so validate-ci sees a fresh snapshot rather than failing and demanding a second invocation."

How it runs

Typical failures and how to fix them

Wiring