diff --git a/packages/studio/src/player/components/TimelineGroupRow.test.tsx b/packages/studio/src/player/components/TimelineGroupRow.test.tsx
new file mode 100644
index 000000000..295d57321
--- /dev/null
+++ b/packages/studio/src/player/components/TimelineGroupRow.test.tsx
@@ -0,0 +1,96 @@
+// @vitest-environment happy-dom
+import React, { act } from "react";
+import { createRoot } from "react-dom/client";
+import { afterEach, describe, expect, it, vi } from "vitest";
+import { TimelineGroupRow } from "./TimelineGroupRow";
+import { TimelineEditProvider } from "../../contexts/TimelineEditContext";
+import { defaultTimelineTheme } from "./timelineTheme";
+import type { TimelineTrackGroupInfo } from "./useTimelineTrackDerivations";
+import type { TimelineElement } from "../store/playerStore";
+
+(globalThis as unknown as { IS_REACT_ACT_ENVIRONMENT: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
+
+vi.mock("../../telemetry/canary", () => ({ isCanaryEnabled: () => true }));
+
+afterEach(() => {
+ document.body.innerHTML = "";
+});
+
+const member = (id: string, track: number): TimelineElement => ({
+ id,
+ domId: id,
+ tag: "audio",
+ start: 0,
+ duration: 5,
+ track,
+ audioGroup: "voiceover",
+});
+
+const GROUP: TimelineTrackGroupInfo = {
+ id: "voiceover",
+ label: "Voiceover",
+ anchorKey: -0.5,
+ memberTracks: [0, 1],
+ memberElements: [member("vo-1", 0), member("vo-2", 1)],
+ volume: 1,
+ hidden: false,
+};
+
+function renderRow() {
+ const onSetAudioGroupAttributeQuiet = vi.fn();
+ const onSetElementAttributeQuiet = vi.fn();
+ const host = document.createElement("div");
+ document.body.append(host);
+ act(() =>
+ createRoot(host).render(
+
+ ({ lanes: [] }) } as never}
+ pps={10}
+ currentTime={0}
+ compositionDuration={60}
+ contentGutter={0}
+ trackContentWidth={800}
+ />
+ ,
+ ),
+ );
+ return { host, onSetAudioGroupAttributeQuiet, onSetElementAttributeQuiet };
+}
+
+describe("TimelineGroupRow", () => {
+ // C1 names this as the step's own definition of done: "opening the popover on
+ // a GROUP and applying a preset results in exactly ONE `data-fx-chain` write,
+ // on the group element, and zero writes on members". A group IS a bus — a
+ // write that fanned out to the members would be batch-apply wearing a bus's
+ // clothes, which is the one thing §1 rules out.
+ it("applies a preset to the group element only, never to its members", () => {
+ const { host, onSetAudioGroupAttributeQuiet, onSetElementAttributeQuiet } = renderRow();
+ const fx = Array.from(host.querySelectorAll("button")).find((b) =>
+ b.getAttribute("aria-label")?.startsWith("Effects"),
+ );
+ act(() => fx?.click());
+ const preset = document.querySelector(".hf-fx-preset-item");
+ act(() => preset?.click());
+
+ expect(onSetAudioGroupAttributeQuiet).toHaveBeenCalledTimes(1);
+ const [groupId, attr] = onSetAudioGroupAttributeQuiet.mock.calls[0] ?? [];
+ expect(groupId).toBe("voiceover");
+ expect(attr).toBe("data-fx-chain");
+ // The members are the point: not one write reaches them.
+ expect(onSetElementAttributeQuiet).not.toHaveBeenCalled();
+ });
+});