From 8fb76a22c090580a12d33be0c7bfe2ba99847cd2 Mon Sep 17 00:00:00 2001 From: Eugenio Valeiras Date: Thu, 30 Jul 2026 18:15:34 -0300 Subject: [PATCH] fix(board): stop truncating workflows longer than 12 columns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `normalizeWorkspaceStatuses` capped the list at 12 with a bare `slice(0, 12)`. Nothing in the UI enforced that cap, so authoring a 13th column appeared to work and the column silently vanished on the next normalize — no error, no warning, no way to tell why. Nothing structural depends on the number. The board already scrolls horizontally and the sidebar groups by status, so extra columns cost nothing; the cap was the only thing standing in the way. This matters for teams mirroring an external workflow. A Jira project with Open / In development / Code review / Deploy DEV / Ready for QA / In QA / Deploy STG / Ready for STG / In STG / Deploy PROD / Done / Blocked / Reopened is already 13 states before counting anything project-specific, so a 1:1 board was simply not expressible. Raised to 64 and documented as what it actually is: a corruption guard, so a damaged payload still cannot explode the board. Same shape as MAX_PERSISTED_PROJECT_GROUP_DEPTH, which carries the same kind of comment. Tests cover both directions — a 20-column workflow survives normalize, and a 500-entry payload is still clamped. --- src/shared/workspace-statuses.test.ts | 24 ++++++++++++++++++++++++ src/shared/workspace-statuses.ts | 8 +++++++- 2 files changed, 31 insertions(+), 1 deletion(-) 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