[eric] canvas: a card placement with no session id is refused and the search palette skips one; a probe once wrote cards[undefined] and the palette threw on every render after

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
ciregenz
2026-09-07 11:43:50 -07:00
co-authored by Claude Fable 5.1
parent 7004555f85
commit 8b4191ef95
3 changed files with 21 additions and 0 deletions
@@ -37,6 +37,8 @@ const CardSearchPalette: React.FC<Props> = ({
const items = useMemo((): CardSearchItem[] => {
const result: CardSearchItem[] = [];
for (const card of Object.values(cards)) {
// A layout entry without a session cannot be searched or focused; one such entry took the whole palette down on every render.
if (typeof card.session_id !== 'string') continue;
const session = sessions[card.session_id];
result.push({
id: card.session_id,
@@ -806,6 +806,8 @@ const dashboardLayoutSlice = createSlice({
}>
) {
const { sessionId, x, y, width, height, expandedSessionIds, exact } = action.payload;
// A card keyed "undefined" persists, survives every reload, and threw inside the search palette on each render (a probe once dispatched the wrong key); the bad state is unwritable here.
if (typeof sessionId !== 'string' || !sessionId) return;
const pos = exact ? { x, y } : findOpenSpotNear(x, y, collectOccupiedRects(state, expandedSessionIds), width, height);
state.cards[sessionId] = {
session_id: sessionId,
@@ -0,0 +1,17 @@
import { test } from 'node:test';
import assert from 'node:assert/strict';
import dashboardLayoutReducer, { placeCard } from './dashboardLayoutSlice';
// A drill dispatched placeCard without a sessionId and the reducer wrote cards["undefined"], which persisted and made the
// search palette throw on every render until the file was edited by hand. The bad state is unrepresentable now.
test('placeCard without a session id writes nothing', () => {
const before = dashboardLayoutReducer(undefined, { type: 'init' });
const after = dashboardLayoutReducer(before, placeCard({ x: 1, y: 2, width: 100, height: 100 } as unknown as Parameters<typeof placeCard>[0]));
assert.deepEqual(Object.keys(after.cards), Object.keys(before.cards));
assert.ok(!('undefined' in after.cards));
});
test('placeCard with a session id still places', () => {
const after = dashboardLayoutReducer(undefined, placeCard({ sessionId: 's1', x: 1, y: 2, width: 100, height: 100, exact: true }));
assert.equal(after.cards.s1.x, 1);
});