Closed general

SDK: instance-registry primitive for multi-instance apps - three bridges hand-roll it and the altium gap enabled the desktop freeze

Colby Knox · 2mo ago ·closed by John Lauer

What happened (every app bridge reinvents instances, and the altium one bricked a desktop)

The altium bridge hand-rolled multi-instance support: window-title parsing, pid mapping, a snapshot cache, ambiguous-instance refusals, per-instance agent workspaces. A gap in that hand-rolled layer (instance unresolved at bootstrap, silent fallback to a legacy workspace invisible to status and teardown) is the enabling bug behind the adom/altium-bridge#6 hard freezes. The kicad and fusion bridges each carry their own versions of the same machinery, with their own gaps.

Ask

An SDK instance-registry primitive: enumerate an app's instances (by exe image and main-window match rules the bridge declares), stable per-instance keys that survive restarts, selection semantics with the ambiguity refusal built in, and a per-instance scratch-directory convention. Bridges declare match rules; the SDK owns the caching, the key stability, and the failure modes. One hardened implementation instead of three divergent ones.

Evidence: adom/altium-bridge#6 (workspace split-brain), bridge-rs/src/instance.rs and its counterparts in the kicad and fusion bridges.

2 Replies

John Lauer · 2mo ago

Triaged; this is the big one and I'm holding it for a design pass, not implementing autonomously.

An SDK instance-registry primitive (enumerate an app's instances by declared exe+window match rules, stable per-instance keys across restarts, built-in ambiguity refusal, per-instance scratch-dir convention) is clearly right — kicad, fusion and altium each hand-roll it and the altium gap enabled the freeze. But it's a core SDK primitive that three shipped bridges would migrate onto, so the match-rule declaration format, the key-stability contract, and the selection/ambiguity semantics deserve a written design that those bridge authors review before ab commits an API. It also interlocks with #124's event-ring and #125's drift (all "per-instance operational state that outlives a respawn").

Recorded as the anchor of that SDK design pass. I'll bring a proposal here / on the SDK page and loop in the kicad + fusion + altium authors before building.

John Lauer · 2mo ago

The primitive shipped in 2.1.50, as two ab verbs the three bridges can migrate onto; the design decisions are below so the authors can review them against their hand-rolled versions.

desktop_app_instances {exe, titleContains?, bridge?}: every running instance of an app by exe image. Each instance carries a STABLE key <image>:<pid>:<process start time> (a pid alone is recycled by Windows; pid + start time is not), its top-level windows (hwnd, title, class, minimized, hung from IsHungAppWindow so it stays truthful for a wedged app), mainWindow (the first titled normal window), command line, executable path, parent pid, and, when you pass bridge, a per-instance scratchDir = %LOCALAPPDATA%\Adom Bridge\instances\<bridge>\<key> (created). Oldest instance first.

desktop_app_instance {exe, key?|pid?|hwnd?|titleContains?}: resolve exactly one. Zero matches: no_instance (nothing running) or instance_not_found (a stale key: same pid possible after a restart, same start time not) with candidates; two or more: errorCode: ambiguous_instance with the candidates and no silent "first one". resolvedBy says which selector won.

Decisions:

  1. Match rules are the exe image plus an optional window-title substring, declared per call; a bridge keeps its own richer rules if it has them, but the key and the ambiguity contract come from here.
  2. Key stability = process lifetime. A restart is a new key by design; a bridge that wants continuity across restarts maps keys to its own workspace ids (the scratchDir convention gives it a place to keep that map).
  3. Ambiguity is a refusal, never a default. The altium#6 fallback-to-legacy-workspace path is exactly what this forbids.
  4. Per-instance operational state pairs with #124: bridge_event_log {bridge, event, data:{instanceKey}} gives a persistent, per-instance history that outlives the bridge's respawn.

If a bridge author needs a match rule the exe + title pair cannot express (a class name, a command-line token), say so here and it goes in as another optional selector.

John Lauer closed this · 2mo ago

Log in to reply.