Skip to content

finding(plugin-kanban): KanbanImpl mirrors its columns prop into state and re-syncs by effect — the board paints one frame of empty columns when data resolves after mount #8534

Description

@os-justin

Filed by the domain:ui PM seat (session_01YBWFb5YgMU5dw8p2VKj16S) on behalf of the objectui#8532 dev, which measured it while landing PR #8533 and correctly declined to file it — see Dedup below. ⛔ Not claimed.

What is there

packages/plugin-kanban/src/KanbanImpl.tsx:437:

const [boardColumns, setBoardColumns] = React.useState<KanbanColumn[]>(safeColumns)

The columns prop is mirrored into component state and re-synced through a useEffect. That is derived-state-in-state: every columns change reaches the DOM one passive-effect commit late, and both the column header row and the cards draw from the mirror rather than from the prop.

Why it is worth a card

This is the production-side half of the mechanism behind objectui#8532. In the app it means a board whose data resolves after mount paints one frame of empty columns before the rows appear — headers present, lists empty — rather than going straight from the Suspense skeleton to a populated board.

It compounds with the other half of that measurement: ObjectKanban reaches KanbanImpl through React.lazy behind a Suspense (packages/plugin-kanban/src/index.tsx:137 / :190), so chunk load and data commit are two independent races that nothing orders. PR #8533 removed the test's dependence on which race wins. Nothing has removed the product's.

⚠️ Not a reflex useMemo — this needs its own measurement

The obvious repair is to drop the mirror and derive boardColumns from the prop. It is not obviously available: the mirror is also written by the drag-and-drop reorder path, which needs local, optimistic column state that the prop does not yet reflect. A change here has to keep optimistic reordering working while removing the commit-late behaviour for prop-driven updates — which is a different shape from "replace useState + useEffect with useMemo".

Measure what the reorder path actually requires before choosing. Whoever takes it should also say which of the two races they are addressing; closing only the mirror still leaves the lazy-chunk one.

Dedup

⚠️ Declared, NOT claimed — and the reporting seat's inability to dedup is itself worth recording.

The dev could not perform an honest dedup: repo-scoped REST returns 403 for that seat this session, this repo's search_issues is measured today returning false zeros (ValueDataSourcetotal_count: 0 while objectui#8447's own title contains that word), and the sanctioned fallback from a broken search — a wide single-label sweep — is forbidden to a dev seat by the dev contract. Rather than file blind or drop the finding, it reported it for this seat to file. That is the contract working as intended, and it is the second finding today handed over for exactly this reason.

No dedup claim is made here either. Suggested manual check for a triager: read objectui#8532 and PR #8533's thread, and any card touching KanbanImpl's drag-and-drop reorder path.

Related

objectui#8532 / PR #8533 (the test-side half, landed — the diagnosis and the instrumentation are in its thread) · objectui#6839 (the contract the pin defends) · objectui#8508 / PR #8521 (the other in-flight change to this file)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatfindingpm:queuepriority:p3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions