Expand description
Runtime-side convergence machinery for the UI-improvement loop.
The agent itself is stateless about loop-level concerns: it decides one patch at a time, on the current report, with a double-patch guard for the same render. What it cannot see is the temporal shape of its own decisions across renders — whether successive reports are walking through the same patch over and over (A→B→A oscillation), or whether the loop is making forward progress.
That observation belongs to the caller, per neo’s review: “controllers use workqueue backoff; reconcilers stay stateless.” This module owns the per-surface history needed to detect oscillation and short-circuit the apply path when one is suspected.
Structs§
- Iteration
Budget - Per-surface iteration budget. Counts agent-driven patches per
surface; once a surface hits the cap, the handler short-circuits
the agent entirely until the surface is reset (typically via
delete_surface+create_surface, or an explicitreset). - Oscillation
Detector - Per-surface oscillation detector. Records recent
patch_hashvalues fromDecision::Patchoutcomes and reports whether a fresh proposal would repeat one we’ve seen recently — that’s the A→B→A pattern the loop must not commit to.
Constants§
- DEFAULT_
MAX_ ITERATIONS - Maximum agent-driven patches per surface before the runtime
hard-stops the loop. Picked to be comfortably larger than the
strategy library’s typical convergence depth (1-2 rounds for the
builtin strategies, 3-5 plausibly for richer libraries) while
being tight enough that an oscillating or buggy strategy can’t
run away. Tunable per-process by replacing the
IterationBudget::newcall withIterationBudget::with_max. - HISTORY_
DEPTH - Number of recent patch hashes retained per surface. Tuned for
the v1 loop where strategies converge in 1-2 rounds; oscillation
signals are typically
last == current, so a small window is plenty. Bumping this hurts cache locality without paying for itself until patch graphs get wider.