Compositor-agnostic snap-zone state cache.
Maps a window to the snap-zone UUID it occupies. A window is "snapped" iff it has a non-empty zone entry; a floating or unmanaged window carries no entry. Sibling of FloatingCache — together the two describe a window's placement for the IsSnapped / Zone / IsFloating window-rule match fields. Both caches key per-instance state by the stable instanceId (below); FloatingCache additionally carries an app-wide appId keyspace (a bare appId, e.g. a session-restore marker floating every instance of an app).
Keyed by the STABLE instanceId, not the full composite windowId. A window's appId can mutate mid-session (Electron / CEF apps rename their window class), which changes the composite appId|instanceId but never the instanceId. Keying by instanceId keeps a snapped window's zone resolvable across that rename, so a Zone / IsSnapped rule keeps matching it. All accessors take the composite windowId and extract the instanceId internally, so callers stay composite-id-based. A bare appId (no | separator) is its own instanceId per extractInstanceId, so it degrades gracefully.