From 66b10156e435bb35c7aac8cbffbfae75ea56a9f8 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Fri, 7 Aug 2026 17:13:31 +0200 Subject: [PATCH] Keep the agent mark fallback from stranding on a missing -light twin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The panel resolves marks by walking assets/-light.svg then assets/.svg, advancing on Image.Error. But the candidates binding is re-evaluated whenever the provider objects are rebuilt, and a fresh array identity with identical content reset the walk to the -light candidate. Re-pointing source at a URL whose load already failed emits no statusChanged, so the walker never advanced again and agents that ship a single mark — Claude — fell back to the generic bar glyph on light surfaces. Key the reset on the candidate URLs instead of the array identity, and defer the error advance one tick so stepping source from inside its own status change doesn't trip the binding-loop detector. Co-Authored-By: Claude Fable 5 --- shell/plugins/agents/Panel.qml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/shell/plugins/agents/Panel.qml b/shell/plugins/agents/Panel.qml index e1489829..5076980a 100644 --- a/shell/plugins/agents/Panel.qml +++ b/shell/plugins/agents/Panel.qml @@ -367,8 +367,14 @@ Panel { Item { id: heroMark property var candidates: root.iconCandidatesForProvider(root.provider, root.surface) + // Provider objects are rebuilt on every refresh, which churns the + // array's identity without changing its content. Restart the fallback + // walk only when the URLs change: re-pointing source at a URL whose + // load already failed emits no statusChanged, so an identity-only + // reset would strand the walker on a missing -light twin. + property string candidatesKey: candidates.join("\n") property int candidateIndex: 0 - onCandidatesChanged: candidateIndex = 0 + onCandidatesKeyChanged: candidateIndex = 0 width: Style.font.display height: Style.font.display @@ -380,7 +386,10 @@ Panel { sourceSize.width: Style.font.display * 2 sourceSize.height: Style.font.display * 2 fillMode: Image.PreserveAspectFit - onStatusChanged: if (status === Image.Error && heroMark.candidateIndex < heroMark.candidates.length) heroMark.candidateIndex++ + // Advancing source from inside its own status change trips the + // binding-loop detector; defer the step one tick. + onStatusChanged: if (status === Image.Error && heroMark.candidateIndex < heroMark.candidates.length) + Qt.callLater(function() { heroMark.candidateIndex++ }) } Text {