diff --git a/surfaces/gui/e2e/sidebar-sessions.spec.ts b/surfaces/gui/e2e/sidebar-sessions.spec.ts
index 5b997399..35534f82 100644
--- a/surfaces/gui/e2e/sidebar-sessions.spec.ts
+++ b/surfaces/gui/e2e/sidebar-sessions.spec.ts
@@ -7,12 +7,13 @@ import { test, expect } from "./fixtures";
test("session list caps at the peek count with Show more", async ({ page }) => {
await page.goto("/");
- // Boot resumes a cowork session, so the Coworker accordion body is expanded.
+ // Boot resumes a cowork session, so the Coworker accordion body is expanded. The body holds
+ // 8 sessions (7 weekly plans + the Slack-origin one, §31 rev) against sessions_peek=5.
await expect(page.getByTitle("Weekly plan 1")).toBeVisible();
await expect(page.getByTitle("Weekly plan 5")).toBeVisible();
await expect(page.getByTitle("Weekly plan 6")).toHaveCount(0);
- await page.getByRole("button", { name: "Show more (2)" }).click();
+ await page.getByRole("button", { name: "Show more (3)" }).click();
await expect(page.getByTitle("Weekly plan 6")).toBeVisible();
await expect(page.getByTitle("Weekly plan 7")).toBeVisible();
});
@@ -42,26 +43,23 @@ test("archive via the row menu is reversible via the Archived disclosure", async
await expect(page.getByTitle("Weekly plan 2")).toBeVisible();
});
-test("mention-spawned sessions collapse under From Slack with the platform icon (§31)", async ({
+test("mention-spawned sessions list in Recent with the platform icon — no From Slack band (§31 rev)", async ({
page,
}) => {
+ // Flat chronological layout — the launch default (personas off).
+ await page.route("**/v1/settings", (r) => r.fulfill({ json: { nav_layout: "flat" } }));
await page.goto("/");
await expect(page.getByTitle("Weekly plan 1")).toBeVisible();
- // Collapsed by default with a count; the session row hidden until expanded…
- const toggle = page.getByTestId("from-slack-toggle");
- await expect(toggle).toContainText("From Slack (1)");
- await expect(page.getByTitle("#general — check the deploy?")).toHaveCount(0);
-
- await toggle.click();
+ // No collapsed band; the session sits directly in Recent, exactly once (its fixture
+ // timestamp sorts it past the peek cap, so expand first)…
+ await expect(page.getByTestId("from-slack-toggle")).toHaveCount(0);
+ await page.getByText(/Show \d+ more/).click();
const row = page.getByTitle("#general — check the deploy?");
await expect(row).toBeVisible();
- // …wearing the Slack logo (hover-hidden cluster, so assert attachment not visibility)…
- await expect(
- page.getByTestId("from-slack-list").locator('[data-logo="slack"]'),
- ).toHaveCount(1);
- // …and never duplicated into any other list.
await expect(page.getByTitle("#general — check the deploy?")).toHaveCount(1);
+ // …wearing the Slack logo (hover-hidden cluster, so assert attachment not visibility).
+ await expect(row.locator('[data-logo="slack"]')).toHaveCount(1);
});
test("pin via the row menu moves the session to the Pinned band and back", async ({ page }) => {
diff --git a/surfaces/gui/src/components/Sidebar.test.tsx b/surfaces/gui/src/components/Sidebar.test.tsx
index b1aea346..81d69e16 100644
--- a/surfaces/gui/src/components/Sidebar.test.tsx
+++ b/surfaces/gui/src/components/Sidebar.test.tsx
@@ -179,7 +179,7 @@ describe("From Slack group (§31)", () => {
origin_label: "#general · T0AB",
};
- it("mention-spawned sessions collapse under From Slack with the platform icon, out of Recent", async () => {
+ it("mention-spawned sessions list chronologically in Recent with the platform icon (no band)", async () => {
stubFetch([
{ match: "/v1/personas", method: "GET", json: PERSONAS },
{ match: "/v1/settings", method: "GET", json: { nav_layout: "flat" } },
@@ -187,20 +187,14 @@ describe("From Slack group (§31)", () => {
render();
await screen.findByText("incident watch"); // flat Recent rendered
- // Collapsed by default: the header shows a count, the row itself is hidden…
- const toggle = screen.getByTestId("from-slack-toggle");
- expect(toggle.textContent).toContain("From Slack (1)");
- expect(screen.queryByText("#general — check the deploy?")).toBeNull();
-
- // …and the session does NOT duplicate into the chronological Recent list.
- fireEvent.click(toggle);
+ // No collapsed band — the session sits directly in the Recent list, exactly once…
+ expect(screen.queryByTestId("from-slack-toggle")).toBeNull();
const row = await screen.findByText("#general — check the deploy?");
expect(screen.getAllByText("#general — check the deploy?")).toHaveLength(1);
- // The row wears the Slack logo, right-aligned in the indicator cluster.
- const list = screen.getByTestId("from-slack-list");
- expect(list.querySelector('[data-logo="slack"]')).toBeTruthy();
- expect(row).toBeTruthy();
+ // …wearing the Slack logo in the row's indicator cluster.
+ const cluster = row.closest(".group");
+ expect(cluster?.querySelector('[data-logo="slack"]')).toBeTruthy();
});
});
diff --git a/surfaces/gui/src/components/Sidebar.tsx b/surfaces/gui/src/components/Sidebar.tsx
index 0b532f95..06e718b2 100644
--- a/surfaces/gui/src/components/Sidebar.tsx
+++ b/surfaces/gui/src/components/Sidebar.tsx
@@ -339,15 +339,9 @@ export function Sidebar(props: Props) {
const pinnedSessions = props.sessions.filter(
(s) => s.pinned && !s.session_id.startsWith("__") && !s.archived,
);
- // §31: mention-spawned sessions gather in one cross-persona "From Slack" group, collapsed by
- // default (owner call 2026-07-13; no auto-archive — a future global setting). Pinned wins.
- const slackSessions = props.sessions
- .filter(
- (s) =>
- s.origin === "slack" && !s.archived && !s.pinned && !s.session_id.startsWith("__"),
- )
- .sort((a, b) => (b.updated_at || "").localeCompare(a.updated_at || ""));
- const [slackOpen, setSlackOpen] = useState(false);
+ // §31 (revised 2026-07-21): mention-spawned sessions list chronologically in Recent like any
+ // other session — the OriginIcon in the row's indicator cluster marks where they came from.
+ // The separate collapsed "From Slack" band hid fresh mentions below week-old sessions.
// A row in the account menu (§26): closes the menu, then runs the destination.
const appMenuItem = (
icon: IconName,
@@ -411,9 +405,7 @@ export function Sidebar(props: Props) {
// EXCLUDED here: they live in the cross-persona Pinned band only, so they don't repeat inside the
// persona group / project list (matching the flat layout's Recent, which also drops pinned).
const all = props.sessions.filter((s) => s.agent === browseKey && !s.session_id.startsWith("__"));
- // Origin (mention-spawned) sessions live in the cross-persona "From Slack" band, not the
- // persona lists — pinned still wins (Pinned band), and archived keeps the persona disclosure.
- const mine = all.filter((s) => !s.archived && !s.pinned && !s.origin);
+ const mine = all.filter((s) => !s.archived && !s.pinned);
const archived = all.filter((s) => s.archived);
// Only PROJECT-SCOPED personas group sessions by project (git-bound Code, project-bound Ops).
// Scratch/deliverable conversations are orphan (each has its own per-conversation scratch dir),
@@ -429,7 +421,7 @@ export function Sidebar(props: Props) {
// Recent = every non-pinned, non-archived, real session across ALL personas, newest first
// (by updated_at; missing timestamps keep store order), search-filtered. Drives the flat layout.
const recentSessions = [...props.sessions]
- .filter((s) => !s.archived && !s.session_id.startsWith("__") && !s.pinned && !s.origin)
+ .filter((s) => !s.archived && !s.session_id.startsWith("__") && !s.pinned)
.filter((s) => personaVisible(s.agent))
.filter(matches)
.sort((a, b) => (b.updated_at || "").localeCompare(a.updated_at || ""));
@@ -705,27 +697,6 @@ export function Sidebar(props: Props) {
) : null;
- // §31: the collapsed cross-persona "From Slack" band — mention-spawned sessions, both layouts.
- // Disclosure shape mirrors the persona body's Archived row.
- const fromSlackBand = () =>
- slackSessions.length > 0 ? (
-
-
- {slackOpen && (
-
- {slackSessions.map((s) => cardRow(s))}
-
- )}
-
- ) : null;
-
// RECENT header with the group/filter control (§20) — the group toggle moved off the brand bar.
// "Group by" flips the persona accordion ↔ chronological list; "Filter by coworker" narrows to
// the checked personas (none checked = all shown).
@@ -1075,7 +1046,6 @@ export function Sidebar(props: Props) {