diff --git a/src/shared/workspace-statuses.test.ts b/src/shared/workspace-statuses.test.ts index 9d3e881345a..2c46a41aae7 100644 --- a/src/shared/workspace-statuses.test.ts +++ b/src/shared/workspace-statuses.test.ts @@ -10,6 +10,30 @@ import { } from './workspace-statuses' describe('workspace status visuals', () => { + it('keeps workflows longer than a dozen columns', () => { + // Why: mirroring an external workflow (Jira, Linear) routinely needs more + // than a dozen states. The old cap of 12 dropped the extra ones on the + // next normalize, with no error and nothing in the UI preventing them. + const authored = Array.from({ length: 20 }, (_, index) => ({ + id: `state-${index}`, + label: `State ${index}` + })) + + const statuses = normalizeWorkspaceStatuses(authored) + + expect(statuses).toHaveLength(20) + expect(statuses.at(-1)).toMatchObject({ id: 'state-19', label: 'State 19' }) + }) + + it('still truncates absurd payloads so corrupted data cannot explode the board', () => { + const corrupted = Array.from({ length: 500 }, (_, index) => ({ + id: `state-${index}`, + label: `State ${index}` + })) + + expect(normalizeWorkspaceStatuses(corrupted).length).toBeLessThanOrEqual(64) + }) + it('keeps the default workflow order', () => { expect(cloneDefaultWorkspaceStatuses().map((status) => status.id)).toEqual([ 'todo', diff --git a/src/shared/workspace-statuses.ts b/src/shared/workspace-statuses.ts index b3aa587043b..245ebee1ab6 100644 --- a/src/shared/workspace-statuses.ts +++ b/src/shared/workspace-statuses.ts @@ -9,7 +9,13 @@ export { DEFAULT_WORKSPACE_STATUSES } from './workspace-status-defaults' const WORKSPACE_STATUS_GROUP_PREFIX = 'workspace-status:' const MAX_STATUS_LABEL_LENGTH = 32 -const MAX_WORKSPACE_STATUSES = 12 +// Why: corruption guard only — nothing in the board or the sidebar depends on +// this number, and the renderer never enforces it, so a low cap just truncated +// legitimate columns on the next normalize. Teams mirroring an external +// workflow (Jira, Linear) routinely need more than a dozen states; the board +// already scrolls horizontally and groups by status, so the extra columns cost +// nothing structurally. +const MAX_WORKSPACE_STATUSES = 64 type WorkspaceStatusNormalizationOptions = { migrateDefaultWorkflowStatuses?: boolean migrateLegacyDefaultStatusVisuals?: boolean