Skip to content

Add Kevin AI support chat to the studio footer - #6159

Open
AnkhHeart wants to merge 18 commits into
masterfrom
ankh/ai-chat-v3
Open

Add Kevin AI support chat to the studio footer#6159
AnkhHeart wants to merge 18 commits into
masterfrom
ankh/ai-chat-v3

Conversation

@AnkhHeart

Copy link
Copy Markdown
Contributor

Summary

  • Adds the Kevin AI support chat: a footer icon that opens a Streamlabs-API-backed support window (transcript, suggested prompts, inline markdown replies, tool approvals) replacing the chat tab that lived in the stream-avatar plugin.
  • Wires the chat onto the /v2 protocol, exposing OBS tools (scenes, sources, streaming, replay) and Desktop-side agent tools (mic filters, stream health, diagnostics, support tickets) for the agent to call.
  • Adds an interaction-quota meter and Ultra/Ultra+ upsell mirroring the Automations usage meter, including refusal-path fixes (stuck spinner, duplicate limit banner, silent re-refusal).
  • Restyles the chat surface to match the latest Figma: footer icon placement next to the notifications bell, new empty-state icon, updated suggested-prompt chips (distinct label vs. sent message), per-message agent avatar, a send-button icon, and bubble/color/spacing updates.

Test plan

  • yarn typecheck (already run clean during development)
  • yarn eslint on touched files (already run clean during development)
  • Manually open the studio footer, log in, and verify the Kevin icon sits directly left of the notifications bell
  • Send a message and confirm the transcript, agent avatar, and bubble styling render correctly in both day and night themes
  • Trigger a tool approval (via a voice request through the avatar plugin) and confirm it renders inline
  • Exhaust the interaction quota and confirm the upgrade modal appears instead of the chat silently failing

Adds a Kevin chat-bubble icon to the studio footer that opens a
"Streamlabs Desktop Support" window backed by the stream-avatar API.
This replaces the chat tab that lived in the stream-avatar plugin.

- KevinSupportService: worker-side StatefulService owning the Socket.IO
  connection and the transcript, so the conversation survives the window
  being closed and reopened. Desktop is on socket.io-client@2, which has
  no `auth` option, so the JWT goes in the query string; the server-side
  role then defaults to `desktop`, which keeps TEXT packets on the
  originating socket and away from the avatar browser sources. Waits for
  the server's `authenticated` event before emitting, since a text
  message sent ahead of `setGame` would run against the default agent.
- KevinSupport: empty state, suggested prompts, transcript and composer.
  Replies are inline markdown only (links, emphasis, code spans), so a
  small splitter renders them rather than pulling in react-markdown.
- Opened via createOneOffWindow rather than showWindow: there is only one
  shared `child` window, and support needs to sit alongside whatever the
  user is asking about.

No API changes were needed — `setGame: STREAMLABS` selects the existing
Support Bot persona.
The support chat moves to the /v2 namespace. socket.io-client 2.x cannot send
a handshake auth object, so the JWT goes in the query string and the server
accepts both.

KevinSupportService connects in init() rather than on component mount. An
approval can be triggered by a voice turn in the plugin while no chat window
is open, and if Desktop is not attached at that moment the request is routed
to the plugin instead — so the connection has to outlive the UI.
surfaceApproval() opens or focuses the chat window when one arrives.

AgentToolsService exposes eight OBS actions (scenes, sources, streaming,
replay) that the agent can call. Desktop is preferred over the plugin for
these because it owns the OBS state directly.

Approval cards render inline in the transcript. The empty state previously
keyed off message count alone, which hid a pending approval on a fresh chat.
handleText dropped every packet with kind === 'links'. That was written on the
assumption the footer was a plugin concern, but the plugin's chat tab is gone
and Desktop is now the only surface that renders text at all.

The footer appends to the reply it belongs to, or opens its own bubble when the
question was asked by voice and the spoken answer never came through here.
renderText already linkifies markdown and opens URLs externally.
The contract is copied byte-for-byte from stream-avatar-api, which formats with
different rules, so `yarn eslint --fix` rewrote it on every run. The sync guard
now compares a normalized form instead of raw bytes, so each repo can format its
copy however it likes. No semantic change.
The plugin gains audio_set_muted and change_filter. Desktop implements neither,
and correctly so — both are executors: ["app"] and route to the plugin — but the
contract is copied byte-for-byte across all three repos, so its copy moves too.

Formatted by this repo's Prettier rather than the API's; the sync guard compares
a normalized form, so the copies no longer have to agree on quotes or wrapping.
The Desktop half of the Sidekick support set.

mic_enhance picks a filter chain from what the streamer says is wrong.
general, background_noise, too_quiet and uneven_volume each get their own
filters and values — a gate tuned for a quiet room does nothing in a noisy
one, and compressing someone who is simply too quiet without makeup gain
leaves them quieter still. too_quiet makes up level through the
compressor's output_gain, since TSourceFilterType has no standalone gain
filter, with a limiter so that gain cannot clip. echo applies nothing and
explains why: no OBS filter removes room reverb, and the real fixes are
headphones, mic placement and soft furnishings.

Anything this service adds is named with a "Sidekick " prefix, and removal
matches the prefix rather than the chosen preset — switching from too_quiet
to background_noise must not leave the limiter stacked underneath, and
asking twice must not end up with two gates fighting each other.

The mic is resolved rather than asked for: Mic/Aux is the app's own default
name, with a "mic" prefix match for anyone who renamed theirs.

stream_health returns what PerformanceService already tracks plus the
resolutions, so a question about dropped frames can be answered from the
real numbers instead of guessed at.

diagnostics_report uploads and returns the report code. support_open_ticket
opens the same Zendesk form Settings > Get Support links to.

Tool protocol version goes back to 1: v2 has not shipped, so there is no
released client to be older than anything, and every client advertises this
constant anyway.
Mirrors the Automations usage meter: a counter in the top right of the
support modal, and the same upgrade modal when the allowance runs out.

support-limits.tsx is the sibling of automations-limits.tsx and follows it
deliberately — same promptAction, same UltraIcon, same free -> Ultra ->
Ultra+ -> hard cap ladder. The refl is 'slobs-support-chat' rather than
'slobs-automations' so the two upsells stay separable in the conversion
funnel instead of blending into one number.

The meter does not wait for the server. Counts arrive on v2:rateLimit, but
only once a request has been handled, so gating the render on them left the
meter absent until after the first message — exactly when someone on the
free tier most wants to see their allowance. It renders 0/limit from the
tier and the server's figures replace that when they land, which is how the
Automations meter derives its numbers too.

Three faults in the refusal path came out of reviewing it against the
Automations flow:

The chat bricked at the limit. A refused request never starts a run, so
v2:run.ended never arrived and nothing cleared `pending`: the spinner span
forever and Send stayed disabled. Any v2:error now ends the turn.

The limit was announced twice. v2:error{rate_limit} also set the red banner,
so a raw "You have reached your usage limit." appeared alongside the modal.
Only one of the two is actionable, so quota is now the modal's alone; auth
still surfaces as a banner.

It prompted once, then went silent. The effect was keyed on `exceeded`,
which latches true for the rest of the period, so a second attempt was
refused with no feedback at all once the banner was gone. The service counts
refusals and the modal answers every one, as Automations does per blocked
action.

Also: supportTier now reads UserService.views.tier directly. That getter
already resolves the whole ladder, and wrapping it in an isPrime check
returned 'free' for anyone whose tier was set but whose isPrime was not.

Note the caveat automations-limits already carries: if the API only ever
returns 'free' and 'ultra', the Ultra+ branch is unreachable and an Ultra+
user is offered an upgrade they hold. The server's limiter assumes the
mirror image — tier === 'ultra' ? 1000 : 5000 — so that wants confirming.
…estyle bubbles, add agent avatar and send icon, update suggested prompts
Copilot AI lite review requested due to automatic review settings September 4, 2026 16:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

It introduces user-facing and operational issues (production logging of sensitive chat/tool payloads, silent non-auth socket errors, and missing accessible labeling/focus) that should be corrected before approval.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds a new “Kevin” AI support chat entry point in the Studio footer and introduces the Desktop-side worker service + /v2 protocol contract needed to connect to Streamlabs’ agent API, execute approved tools, and surface quota/upsell UI.

Changes:

  • Adds a Studio footer icon that opens a dedicated “Kevin Support” one-off window.
  • Introduces a worker-window KevinSupportService + AgentToolsService to connect to /v2, handle approvals, and execute Desktop tools.
  • Adds new UI surface (chat window, icons, styling) and associated i18n + analytics/upsell wiring.
File summaries
File Description
app/services/windows.ts Registers KevinSupport as a window component.
app/services/usage-statistics.ts Adds analytics event + refl for SupportChat upsell tracking.
app/services/stream-avatar/v2/protocol.ts Adds shared /v2 protocol contract definitions.
app/services/stream-avatar/v2/agent-tools.ts Adds Desktop-executed tool handlers for the agent.
app/services/stream-avatar/kevin-support-service.ts Adds worker-window Socket.IO client + approval/tool dispatch logic.
app/i18n/fallback.ts Includes new stream-avatar agent i18n bundle in fallback.
app/i18n/en-US/stream-avatar-agent.json Adds i18n strings for tool approval UI.
app/i18n/en-US/ai.json Adds i18n strings for the Kevin Support chat UI and upsell.
app/components/shared/ReactComponentList.tsx Exposes KevinSupport to the window system’s React component list.
app/components-react/shared/icons/SendIcon.tsx Adds send icon for the composer button.
app/components-react/shared/icons/KevinChatIcon.tsx Adds Kevin chat icon for footer/empty-state.
app/components-react/shared/icons/index.ts Exports the new icon components.
app/components-react/root/StudioFooter.tsx Adds footer entry point that opens the Kevin Support one-off window.
app/components-react/root/StudioFooter.m.less Styles the new footer icon button.
app/components-react/index.ts Registers KevinSupport in the React component registry.
app/components-react/agent/support-limits.tsx Defines support interaction tiers + upgrade prompting.
app/components-react/agent/KevinSupport.tsx Implements the chat/approval UI, usage meter, markdown-lite rendering.
app/components-react/agent/KevinSupport.m.less Adds styling for the support chat window.
app/app-services.ts Registers KevinSupportService and AgentToolsService in the service registry.
Review details
  • Files reviewed: 19/19 changed files
  • Comments generated: 7
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread app/services/stream-avatar/kevin-support-service.ts
Comment thread app/components-react/agent/KevinSupport.tsx Outdated
Comment thread app/components-react/root/StudioFooter.m.less
Comment thread app/components-react/root/StudioFooter.tsx Outdated
Comment thread app/services/stream-avatar/kevin-support-service.ts
Comment thread app/services/stream-avatar/kevin-support-service.ts
Comment thread app/services/stream-avatar/v2/protocol.ts Outdated
@bundlemon

bundlemon Bot commented Sep 4, 2026

Copy link
Copy Markdown

BundleMon

Files updated (1)
Status Path Size Limits
renderer.(hash).js
10.61MB (+70.6KB +0.65%) -
Unchanged files (3)
Status Path Size Limits
vendors~renderer.(hash).js
4.67MB -
updater.js
115.29KB -
guest-api.js
40.23KB -

Total files change +70.6KB +0.45%

Final result: ✅

View report in BundleMon website ➡️


Current branch size history | Target branch size history

Copilot AI review requested due to automatic review settings September 4, 2026 17:03

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

It introduces a confirmed unsafe external-link handling path and a few user-facing accessibility/error-feedback gaps that should be addressed before merge.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (3)

app/components-react/root/StudioFooter.tsx:167

  • This icon-only button has no accessible name; screen readers will announce it generically as “button”. Add an aria-label (and set type="button" to avoid accidental form submission if this footer is ever rendered inside a form).
          <Tooltip placement="top" title={$t('Streamlabs Desktop Support')}>
            <button className={styles.kevinIcon} onClick={openKevinSupport}>
              <KevinChatIcon />
            </button>

app/components-react/root/StudioFooter.m.less:56

  • The new .kevin-icon style removes the focus outline without providing an alternative focus-visible indicator, which makes keyboard navigation difficult.
  &:focus {
    outline: none;
  }

app/services/stream-avatar/kevin-support-service.ts:224

  • v2:error currently only surfaces an error message for auth failures. For other errors (e.g. protocol/internal), the UI clears pending but shows no feedback, which can look like the send was ignored.
        // Quota is answered by the upgrade modal, not by a red line: showing
        // both says the same thing twice, and only one of them is actionable.
        if (p.code === 'rate_limit') return;
        if (p.code === 'auth') this.SET_ERROR(p.message);
      });
  • Files reviewed: 20/20 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread app/components-react/agent/KevinSupport.tsx Outdated
…support

- Label the footer support button (aria-label + type="button") and restore a
  keyboard focus ring instead of suppressing the outline outright.
- Render agent-supplied markdown links as real anchors, and only hand http(s)
  URLs to openExternal -- other schemes fall back to plain text.
- Surface every non-rate-limit v2:error instead of only auth failures, so a
  protocol or internal error no longer fails silently.
- Clear `connecting` on disconnect; a drop mid-handshake left it stuck on.
- Log wire event names always, payload detail only in dev, to keep chat text
  and tool arguments out of production logs.
- Reword the protocol header constraint that contradicted its own sync manifest.
Copilot AI review requested due to automatic review settings September 4, 2026 19:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The new support-chat connection and quota-upsell flows contain user-visible logic bugs (handshake error handling and repeated upsell prompting) that should be fixed before approval.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (2)

Previously missed (1) — in code that hasn't changed since the last review.

app/components-react/agent/KevinSupport.tsx:210

  • This effect will also run on initial mount. If rateLimitRefusals is already > 0 from a previous session (the service state survives closing the support window), opening the window will immediately re-show the upgrade modal even though the user didn’t just attempt an action. Track the last value and only prompt when the counter increments.

app/services/stream-avatar/kevin-support-service.ts:279

  • The catch block always overwrites state.error with a generic message. If the server already provided a specific error via v2:error (e.g. auth/protocol), that message is briefly set and then replaced by the generic one when the handshake promise rejects.
      this.SET_CONNECTING(false);
      this.SET_CONNECTED(false);
      this.SET_PENDING(false);
      this.SET_ERROR($t('Could not connect to Streamlabs Desktop Support. Please try again.'));
  • Files reviewed: 20/20 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread app/services/stream-avatar/kevin-support-service.ts
@michelinewu michelinewu added the needs QA requires QA testing on the branch before merging label Sep 8, 2026
Copilot AI review requested due to automatic review settings September 9, 2026 17:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The new support socket service can reuse cached auth across logout/account switch and can continue connecting after logout while awaiting a token, which is a correctness/security risk.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

app/services/stream-avatar/kevin-support-service.ts:153

  • openSocket() can continue after a logout that happens while awaiting getToken(), creating a new authenticated socket even though the user is no longer logged in. Add a post-await login check and stop the connection attempt (also clear the connecting flag) to avoid reconnecting after logout.
  • Files reviewed: 21/21 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread app/services/stream-avatar/kevin-support-service.ts
Copilot AI review requested due to automatic review settings September 9, 2026 18:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

It introduces a server-driven tool dispatch path that needs a safer tool-name lookup and includes a new clickable span that isn’t keyboard-accessible.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

app/components-react/agent/KevinSupport.tsx:162

  • The upgrade affordance is a clickable <span>, which is not keyboard-accessible by default and won’t be announced as a button to assistive tech. Add button semantics (role/tabIndex + Enter/Space handling) or use a real <button>/<a> element.
  • Files reviewed: 23/23 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread app/services/stream-avatar/v2/agent-tools.ts
Copilot AI review requested due to automatic review settings September 9, 2026 18:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

There’s a confirmed focus-state initialization bug that can misreport the support window’s focus, and a new clickable <span> upgrade CTA that is not keyboard-accessible.

Review details

Suppressed comments (2)

Previously missed (2) — in code that hasn't changed since the last review.

app/components-react/agent/KevinSupport.tsx:163

  • The upgrade call-to-action is a clickable <span>, which is not keyboard-focusable and won’t be operable via Enter/Space for keyboard/screen-reader users. Make it accessible by adding button semantics (role/tabIndex + key handling) or switching to a real <button> element.
    app/services/windows.ts:510
  • isFocused is only updated via focus/blur events; if the window is shown focused but Electron doesn't emit an initial focus (or the app is inactive on show), WindowsService.state[windowId].isFocused can remain undefined and downstream UI (e.g. the footer approval bubble) may treat the chat as not focused even when it is. Initialize/sync focus state once and on show to avoid a persistent undefined focus state.
  • Files reviewed: 23/23 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Copilot AI review requested due to automatic review settings September 9, 2026 19:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It introduces a new socket protocol plus Desktop-side tool execution/approval flows that can affect streaming behavior and warrants final human verification beyond automated review.

Review details

Suppressed comments (5)

Previously missed (4) — in code that hasn't changed since the last review.

app/components-react/agent/KevinApprovalBubble.tsx:58

  • The bubble position is only re-measured on window resize, but the footer can scroll horizontally and nearby footer content can change width without a resize. That can leave the approval bubble pointing to the wrong place while it is visible.
    app/components-react/agent/KevinApprovalBubble.tsx:70
  • The bubble uses left: anchor.left with a fixed 320px width, which can push the callout partially off-screen (especially since the icon lives near the right side of the footer). Clamp the computed left position to the viewport.
    app/components-react/agent/KevinSupport.tsx:162
  • The upgrade affordance is rendered as a clickable , which is not keyboard-focusable by default and is not announced as a button by assistive tech. Use a (or ) for an interactive control.
    app/i18n/en-US/ai.json:35
  • These strings use "setup" as a verb; grammatically it should be "set up". Since these are user-facing prompts, it’s worth correcting the displayed text (the JSON value) to avoid shipping the error.

This issue also appears on line 40 of the same file.

app/i18n/en-US/ai.json:40

  • This prompt uses "setup" as a verb; grammatically it should be "set up". Adjust the displayed text (JSON value) accordingly.
  "How do I setup Streamlabs Sidekick?": "How do I setup Streamlabs Sidekick?",
  • Files reviewed: 23/23 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Comment thread app/components-react/agent/KevinSupport.m.less Outdated
Comment thread app/components-react/agent/support-limits.tsx Outdated
Comment thread app/components-react/shared/icons/KevinChatIcon.tsx
Comment thread app/components-react/shared/icons/SendIcon.tsx
Comment thread app/services/windows.ts Outdated
Copilot AI review requested due to automatic review settings September 10, 2026 15:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

There are confirmed UI behavior/accessibility issues (approval bubble can drift on footer scroll; upgrade control is not keyboard-accessible as implemented).

Review details

Suppressed comments (2)

Previously missed (2) — in code that hasn't changed since the last review.

app/components-react/agent/KevinApprovalBubble.tsx:58

  • KevinApprovalBubble only re-measures the anchor on window resize. Since the footer is horizontally scrollable (overflow-x: auto) and neighboring footer content can resize, the bubble can drift away from the Kevin icon while pending approvals are showing.
    app/components-react/agent/KevinSupport.tsx:158
  • The upgrade affordance is implemented as a clickable . This is not keyboard-focusable by default and won’t be announced as an interactive control by assistive tech.
  • Files reviewed: 24/24 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Copilot AI review requested due to automatic review settings September 10, 2026 16:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

There are a few concrete UX/correctness issues (approval bubble positioning drift, keyboard accessibility for the upsell control, and a logout/connect race that can reintroduce stale errors) that should be addressed before approval.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (2)

Previously missed (2) — in code that hasn't changed since the last review.

app/components-react/agent/KevinApprovalBubble.tsx:58

  • The approval bubble only re-measures its anchor on window resize. Because the footer can scroll horizontally and adjacent content can change width, the fixed-position bubble can drift away from the icon while it’s visible. Consider also re-measuring on scroll (capture) while show is true so the bubble stays aligned.
    app/services/stream-avatar/kevin-support-service.ts:307
  • openSocket() can still be in-flight when userLogout triggers RESET(). If that connect attempt later fails (timeout/connect_error), this catch block can repopulate state.error after logout, leaving a stale “Could not connect…” message while logged out. Gate the generic error message on userService.isLoggedIn so logout remains clean.
  • Files reviewed: 25/25 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread app/components-react/agent/KevinSupport.tsx
Copilot AI review requested due to automatic review settings September 10, 2026 19:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

There are confirmed accessibility issues in the chat UI controls and a confirmed positioning bug in the footer approval bubble when the footer scrolls/resizes.

Review details

Suppressed comments (3)

Previously missed (2) — in code that hasn't changed since the last review.

app/components-react/agent/KevinApprovalBubble.tsx:58

  • The bubble only re-measures the anchor on window resize, but the footer can scroll horizontally (and adjacent footer content can resize), which will move the icon without updating the bubble position. This can leave the approval prompt detached from the Kevin icon until a resize happens.
    app/components-react/agent/KevinSupport.m.less:96
  • The suggested-prompt buttons remove the focus outline but don’t add a focus-visible replacement, which makes keyboard navigation hard/impossible to see. Add a :focus-visible style (matching other buttons like the footer Kevin icon).

app/components-react/agent/KevinSupport.tsx:153

  • The upgrade affordance is a clickable , which is not keyboard-focusable by default and won’t announce itself as a control to assistive tech. Use a (or an ) so it’s accessible via keyboard and screen readers.
      {atCap && !atTopTier && (
        <span className={styles.upgradeLink} onClick={() => upgrade(p.tier, 'meter')}>
          <UltraIcon type="badge" />
          <span className={styles.upgradeText}>
            {p.tier === 'ultra'
  • Files reviewed: 25/25 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs QA requires QA testing on the branch before merging

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants