diff --git a/__tests__/unit/config/public-directory.test.ts b/__tests__/unit/config/public-directory.test.ts index 3f9e549ca..91afc069d 100644 --- a/__tests__/unit/config/public-directory.test.ts +++ b/__tests__/unit/config/public-directory.test.ts @@ -25,6 +25,25 @@ describe('public-directory', () => { expect(isFixtureGroupTitle('Bitcoin Developers Circle')).toBe(false); }); + // A named-prefix list only knows the shapes it has already met. "Audit Group + // 1783191071580" was not one of them, so it survived into a live account's + // context switcher after its two "Audit WF…" siblings were filtered out. + it('hides audit groups whose wording nobody predicted', () => { + expect(isFixtureGroupTitle('Audit Group 1783191071580')).toBe(true); + expect(isFixtureGroupTitle('Workflow Smoke 1783191071580')).toBe(true); + expect(isFixtureGroupTitle('e2e reset 1783191071580')).toBe(true); + }); + + // The timestamp is what makes the rule safe to widen: a real group is named + // by a person, and people do not append an epoch. This matters here more than + // most products — OrangeCat is heading for governance, where "Audit + // Committee" is a group somebody will genuinely create. + it('leaves real groups alone even when they start with an audit word', () => { + expect(isFixtureGroupTitle('Audit Committee')).toBe(false); + expect(isFixtureGroupTitle('Audit Committee 2026')).toBe(false); + expect(isFixtureGroupTitle('Workflow Design Guild')).toBe(false); + }); + it('treats a profile as fixture if either field matches', () => { expect(isFixtureProfile({ username: 'adelina1996gry', name: 'E2E Reset User' })).toBe(true); expect(isFixtureProfile({ username: 'adelina1996gry', name: 'Adelina' })).toBe(false); diff --git a/src/config/public-directory.ts b/src/config/public-directory.ts index d1e4e62b4..b0e462025 100644 --- a/src/config/public-directory.ts +++ b/src/config/public-directory.ts @@ -57,6 +57,19 @@ const EXACT_FIXTURE_USERNAME_SET = new Set(EXACT_FIXTURE_USERNAMES); const FIXTURE_DISPLAY_NAME = /^(e2e reset user|user)$/i; const FIXTURE_GROUP_TITLE = /^(audit\s+wf|ephemeral\s+verify|workflow\s+audit)/i; +/** + * The named prefixes above are an allow-list of shapes we happened to have seen, + * and audits keep inventing new ones: "Audit Group 1783191071580" survived the + * list above and sat in a live account's context switcher. + * + * So also match the *generating* signature rather than the wording — an + * audit-ish first word followed by the millisecond epoch the fixture appends to + * keep names unique. Keying on the timestamp is what keeps a real group safe: a + * governance product will one day have an "Audit Committee", and it will not be + * called "Audit Committee 1783191071580". + */ +const FIXTURE_GROUP_STAMPED = /^(audit|ephemeral|workflow|e2e|wf\d)\b.*\b\d{10,}$/i; + export function isFixtureUsername(username: string | null | undefined): boolean { const u = (username ?? '').trim(); if (u.length === 0) { @@ -90,5 +103,6 @@ export function isFixtureProfile(profile: { } export function isFixtureGroupTitle(title: string | null | undefined): boolean { - return FIXTURE_GROUP_TITLE.test((title ?? '').trim()); + const t = (title ?? '').trim(); + return FIXTURE_GROUP_TITLE.test(t) || FIXTURE_GROUP_STAMPED.test(t); }