Split out of #2130, which named this and scoped it out ("Adjacent gap (not fixed here)"). Nothing was tracking it.
The gap
AgentDetail.vue resolves ?tab= against a hand-maintained list:
const DEEP_LINK_TABS = ['overview', 'tasks', 'chat', 'reports', 'dashboard', 'logs', 'files',
'schedules', 'credentials', 'skills', 'sharing', 'permissions', 'git', 'folders', 'settings', 'info']
It omits a2a, loops, playbooks, access, nevermined — all of which are real, rendered tabs. A link to any of them falls back to Overview with no error and no banner, on a stopped agent as well as a running one. That is the same silent-drop class as #1672.
Why it is a list at all
The list duplicates knowledge that already exists one screen away. visibleTabs is built with the gates applied (agent.can_share adds access / sharing / permissions / a2a; others are pushed conditionally), so there are two sources of truth for "which tabs exist" and only one of them is maintained when a tab is added.
Suggested fix
Resolve against visibleTabs instead of DEEP_LINK_TABS, keeping TAB_ALIASES for the renamed ids.
That deletes the list rather than extending it, so a future tab is deep-linkable the moment it is added — and it dissolves the open question #2130 raised. #2130 worried that adding the permission-gated ids "needs a non-owner blank-panel decision"; resolving against the tabs the viewer can actually see means a non-owner keeps today's Overview fallback for free, with no new decision and no blank panel.
Worth checking while there: applyDeepLinkRouting runs before await loadAgent() (correctly, per #2130), so visibleTabs may be empty on first pass. The resolution likely needs to re-run once the agent loads — which is a behaviour change to get right rather than assume, since re-applying later is exactly the "overrides the user's click" symptom #2130 fixed. Suggest resolving eagerly against the static superset and re-checking visibility only when the agent arrives, or deferring only the gated ids.
Acceptance criteria
Related: #2130, #1672, #1108
Split out of #2130, which named this and scoped it out ("Adjacent gap (not fixed here)"). Nothing was tracking it.
The gap
AgentDetail.vueresolves?tab=against a hand-maintained list:It omits
a2a,loops,playbooks,access,nevermined— all of which are real, rendered tabs. A link to any of them falls back to Overview with no error and no banner, on a stopped agent as well as a running one. That is the same silent-drop class as #1672.Why it is a list at all
The list duplicates knowledge that already exists one screen away.
visibleTabsis built with the gates applied (agent.can_shareaddsaccess/sharing/permissions/a2a; others are pushed conditionally), so there are two sources of truth for "which tabs exist" and only one of them is maintained when a tab is added.Suggested fix
Resolve against
visibleTabsinstead ofDEEP_LINK_TABS, keepingTAB_ALIASESfor the renamed ids.That deletes the list rather than extending it, so a future tab is deep-linkable the moment it is added — and it dissolves the open question #2130 raised. #2130 worried that adding the permission-gated ids "needs a non-owner blank-panel decision"; resolving against the tabs the viewer can actually see means a non-owner keeps today's Overview fallback for free, with no new decision and no blank panel.
Worth checking while there:
applyDeepLinkRoutingruns beforeawait loadAgent()(correctly, per #2130), sovisibleTabsmay be empty on first pass. The resolution likely needs to re-run once the agent loads — which is a behaviour change to get right rather than assume, since re-applying later is exactly the "overrides the user's click" symptom #2130 fixed. Suggest resolving eagerly against the static superset and re-checking visibility only when the agent arrives, or deferring only the gated ids.Acceptance criteria
?tab=works for every tab the viewer can see, includinga2a,loops,playbooks,access,neverminedRelated: #2130, #1672, #1108