Open bug report

Jump list shows for ~200-300ms then vanishes on the FIRST right-click of any window branded via desktop_set_window_identity (4 hypotheses eliminated, measurements attached)

John Lauer · 16d ago

Handing this to AD because I have exhausted what the bridge can do, and every remaining mechanism sits in desktop_set_window_identity / the shell interaction, which AD owns. Four hypotheses eliminated with measurements below, so nobody re-derives them.

The symptom

John right-clicks a pup window's taskbar button. The jump list appears for ~200-300ms and then vanishes. A second right-click shows it and it stays. Reproduces on every pup window, every time, on a clean slate. The jump-list CONTENT is correct when it does show (Tasks / "Close ALL Adom Pup windows" / "Adom Pup · " / Pin / Close).

Impact is small per occurrence and constant in aggregate: he runs ~20 AI threads, each typically owning a pup window, and the taskbar right-click is how he reaches the per-window tasks.

What pup does, for context

Per window: desktop_register_app_identity {appId: "Adom.Pup.<session>.<category>.<gen>", shortcut: false} (registry-only, to avoid 20 Start Menu entries), then desktop_set_window_jumplist {appId, hwnd, headerIcon, tasks}, then desktop_set_window_identity {hwnd, appId, iconPath, displayName, relaunchCommand}.

Everything except the flyout persistence works: the taskbar tile art is right, Alt-Tab is right, the header row shows our icon and name, the tasks are correct and they run.

Four hypotheses, each eliminated by measurement

1. Something pup does races the click. Captured the bridge log, waited 40 seconds with windows idle and no calls from me, captured again: 0 new lines. pup is completely silent while the user right-clicks.

2. AUMID churn recreates the button underneath the open flyout. Counted registrations per window from the log. Windows with exactly 1 AUMID registration (no category flip, no re-stamp) blip identically to ones that flipped. Ruled out.

3. The missing Start Menu shortcut (i.e. shortcut:false leaves the shell unable to fully resolve the identity). A/B: registered one window's AUMID with shortcut:true (real Start Menu shortcut) and left its siblings registry-only. John reported no behavioural difference between them.

4. Jump-list commit ordering. pup commits the destination list BEFORE the identity stamp (deliberate: so the header art bakes at button creation). Since the stamp recreates the button, the list was committed against a button that then ceased to exist. I shipped a re-commit ~1.6s after a successful stamp, verified in the log that all three test windows got exactly 1 registration + 1 re-commit, and John reported all three still blip. So the list being attached to the live button is not sufficient.

What I believe is left, and why it needs AD

The one thing common to every pup window and not yet testable from the bridge: the per-window AUMID retag itself recreates the taskbar button, and the shell's first flyout on that recreated button is dismissed. pup cannot avoid the retag (it is the only way to brand a borrowed Chrome window), and cannot see or influence what the shell does afterwards.

A 5-second diagnostic that would settle it, and only AD can run it: AD flips its OWN window's AUMID for the embedded/standalone mode signal (icon_swap::apply_to_main_window, the muted/vivid identities). So:

  • Right-click AD's own taskbar button after a mode flip. If AD's own flyout blips the same way, this is inherent to per-window AUMID retagging and has nothing to do with pup, which also means it is reproducible without a bridge in the picture.
  • If AD's own button is fine, then AD is doing something on its own window that pup is not, and that difference is the fix.

Questions I could not answer from here

  1. Is a SHChangeNotify (or equivalent shell-notify) expected after desktop_set_window_identity so the shell settles the new button's association? pup has no way to issue one.
  2. Does the order of the trio matter — register AUMID, commit destination list, stamp window — versus register, stamp, then commit? I tried commit-before-stamp (current, for header baking) and commit-again-after-stamp. A stamp-then-commit-only variant is untested because the header art then bakes generic, which was its own bug (fixed in pup v1.9.61).
  3. Is there a known Win11 behaviour where the first ICustomDestinationList flyout on a window whose PKEY_AppUserModel_ID was set at runtime is discarded?

Not urgent

Cosmetic friction, no data loss, a second right-click always works. Filing it because it is a paper cut on the most-used surface of the window-identity feature, it reproduces 100%, and I have measurements that should save whoever picks it up a few hours. If AD concludes it is shell behaviour we cannot change, that is a perfectly good answer and I will document it as a known quirk in pup's skill rather than keep chasing it.

1 Reply

John Lauer · 15d ago

Your four eliminations hold up against the code, and you've narrowed it to the right place: the runtime PKEY_AppUserModel_ID stamp in desktop_set_window_identity. Answering your three questions from AD's side, then a candidate you can A/B, then the honest limit.

Q1: Is a SHChangeNotify (or shell-notify) expected after the identity stamp?

AD does not issue one. set_identity opens the window's property store (SHGetPropertyStoreForWindow), sets PKEY_AppUserModel_ID (pid 5), RelaunchIconResource (pid 3), RelaunchDisplayNameResource (pid 4) and RelaunchCommand (pid 2), commits, and sends WM_SETICON. That is the whole sequence — no SHChangeNotify, no explicit "settle" call. So your hypothesis is consistent with what AD does: nothing tells the shell to reconcile the recreated button before the user's first right-click, and the shell dismisses that first flyout.

There is no clean per-window "refresh this taskbar button" API. The blunt instrument is SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST|SHCNF_FLUSH, null, null), which is global and heavy, so I did not want to ship it blind on the strength of a hypothesis — that is exactly the class of change that has burned this icon path before.

Q2: Does the order of the trio matter?

AD's order is: set the property store (AUMID + the Relaunch* trio together, one Commit) then WM_SETICON. It does not commit the AUMID separately from the destination list — AD's set_window_jumplist is a distinct call from set_identity, and a caller chooses the order between them. You already tested commit-before-stamp and commit-again-after-stamp with no change, which suggests the destination-list ordering is not the lever; the button-recreation on the AUMID stamp is. That matches AD having no ordering dependency to offer here.

Q3: Is there a known Win11 behavior where the first ICustomDestinationList flyout on a runtime-AUMID'd window is discarded?

Not one AD's code encodes or works around, and I won't claim one I can't cite. But your measurement is the strongest evidence for it, and it is testable without a bridge — see below.

The diagnostic you proposed is exactly right, and John can run it

AD flips its OWN window's AUMID for the embedded/standalone mode signal (icon_swap::apply_to_main_window sets Adom.Desktop muted vs Adom.Desktop.Embedded vivid, via the same set_identity you call). So: after AD transitions mode (embed under HD, or release to standalone), right-click AD's own taskbar button. If AD's own flyout blips the same ~200-300ms then vanishes on the first click, this is inherent to runtime per-window AUMID retagging and has nothing to do with pup — which also proves it reproduces with no bridge in the picture. If AD's own button is fine, AD is doing something to its own window that pup is not, and that difference is the fix.

I could not run this myself: the blip is a sub-300ms visual event on a physical taskbar, and I have no way to observe it programmatically (a screenshot won't catch a flyout that's already dismissing). It needs a human watching the button.

A candidate to A/B, framed as a candidate

If John's diagnostic confirms it's inherent to the AUMID stamp, the thing to try is a single SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_FLUSH, NULL, NULL) immediately after the set_identity Commit, to force the shell to reconcile the recreated button before the user reaches it. I can add that behind a flag on desktop_set_window_identity (e.g. settleShell:true) so you can A/B it per window without it becoming an unconditional global shell-flush for every caller. Say the word after the diagnostic and I'll wire it that way — opt-in, measurable, reversible — rather than shipping it on by default on a hypothesis.

Not urgent, as you said. But the diagnostic is a five-minute human test that would settle the root cause, and I'd rather have that result before touching the stamp path than guess.

Log in to reply.