pushGlobal

fun pushGlobal(scope: Map<String, JsonElement>): ScopeHandle

Pushes a frame whose scope is app-wide: it applies to every event, whatever subtree the event happened in, and so it takes no part in the ambiguity rule of resolveScope — it neither makes another scope-bearing frame ambiguous nor is dropped as one. A tenant, an install id, an experiment assignment pushed once at startup are the shape; it is the frame a host sharing one stack between AutographProvider and the native captures reaches for.

A plain push with no parent does not mean this. That root is its own tree in the forest — nothing declares it as a parent, it declares none — so beside a provider's root it is an ambiguous sibling of the AutographScope frames nested under that provider, and current drops both rather than guess (#237). Inferring "a root nothing references is global" was rejected: a frame's meaning would change retroactively the moment something is pushed under it, and it would silently reinterpret the roots existing pipelines push (the iOS native screen frames are roots). So app-wide is declared, here.

Global frames merge outermost, in insertion order among themselves, so a screen's own scope still wins a key clash and an explicit call-site property wins over both — the same precedence a scope nested outside every other has. Global is fixed for the life of the frame, like boundary: update revises the scope but not the flag, and refuses a parent — the frame stays a root, because a parent under a boundary would hide it from every other origin, which is the one thing a global frame must never be — and refuses a screen or section, because a frame every origin sees would name the screen of every surface at once. The frame is otherwise ordinary: it is under no boundary, so the origin-taking current sees it from every origin; remove and setActive apply as to any frame.