[FF] duo_panel_history_stack_persistence — AI panel history stack sessionStorage persistence
Summary
This issue is to roll out the AI panel history stack persistence feature on production, which is currently behind the duo_panel_history_stack_persistence feature flag.
When enabled, the AI panel persists its full Vue Router (abstract mode) history stack to sessionStorage on every navigation, and replays it on panel init. This makes the in-panel "Go back" button continue to work after a full page reload — without the flag, the panel's navigation history lives entirely in memory and is wiped on refresh.
Owners
- Most appropriate Slack channel to reach out to:
#g_agent_foundations - Best individual to reach out to: @afontaine
Expectations
What are we expecting to happen?
Users who open the AI panel, navigate to a session detail page, and hard-refresh the browser will see the "Go back" button stay visible and functional. Clicking it returns them to the prior in-panel route (e.g. the sessions list).
No behavioural change for users who never close/refresh the panel mid-session, or who keep navigation purely within one tab without using back.
What can go wrong and how would we detect it?
- Replay-failure stranding: if a persisted route name no longer exists (e.g. a route was removed in a later release while a stale stack lives in someone's sessionStorage),
safeRouterPushwill throw during replay. The flag-on branch catches this, clears the corrupt stack, and pushes a mode-aware default route — so worst case is "user lands on the chat or closed route" rather than a broken panel. - Storage growth: stack capped at 200 entries (~16 KB) with truncate-from-oldest semantics; well below sessionStorage's 5 MB limit.
gon.featuresexposure regression: the flag is pushed throughee/lib/ee/gitlab/gon_helper.rb. If that push is dropped in a refactor, the FE checkwindow.gon?.features?.duoPanelHistoryStackPersistencereturnsundefinedand the feature silently disables — matches current behaviour exactly, so safe degrade.
Detection: front-end error monitoring should catch any uncaught replay exceptions (none are expected since the catch is comprehensive). Manual smoke test on staging covers the happy path.
Rollout Steps
Rollout on non-production environments
- Verify the MR is merged and deployed:
/chatops gitlab run auto_deploy status <merge-commit> - Enable globally on non-production:
/chatops gitlab run feature set duo_panel_history_stack_persistence true --dev --pre --staging --staging-ref - Smoke test on
staging-canary: open AI panel → navigate Chat → Sessions → session detail → hard reload → verify Go back button works.
Specific rollout on production
- Enable for GitLab team members first:
/chatops gitlab run feature set --feature-group=gitlab_team_members duo_panel_history_stack_persistence true - Monitor for one business day.
Global rollout on production
- 5%:
/chatops gitlab run feature set duo_panel_history_stack_persistence 5 --actors - 25%:
/chatops gitlab run feature set duo_panel_history_stack_persistence 25 --actors - 50%:
/chatops gitlab run feature set duo_panel_history_stack_persistence 50 --actors - 100%:
/chatops gitlab run feature set duo_panel_history_stack_persistence 100 --actors - Globally enable:
/chatops gitlab run feature set duo_panel_history_stack_persistence true
Cleanup
- After one milestone at 100%, file a follow-up MR to remove the feature flag and the legacy single-route fallback in
restoreLastRoute. TherouteState?.name === defaultRouteshort-circuit in the legacy branch is dead code once the flag is removed. - At that point, also revisit the blocked-state hoist regression — the hoist made the disabled-AND-previously-closed case force-open to the blocked route; consider adding
&& routeState?.name !== defaultRouteto the gate.