mirror of
https://github.com/stablyai/orca.git
synced 2026-10-01 08:01:56 +00:00
Creating a tab from the mobile session strip painted the new tab at the end
of the strip and then visibly jumped it to a different slot a beat later.
The client asked the host to insert the tab after the active tab, but then
predicted a different placement for its own optimistic paint:
afterTabId: activeSessionTabId ?? undefined // host: splice(insertAfter + 1)
...
return [...prev, { ...created, isActive: true }] // client: append
Two independent placements that disagree, so the optimistic frame is wrong by
construction and the tab snaps to its real slot on the next published snapshot.
The disagreement dates to 57a70d2ac0 ("Fix mobile session tab authority"),
which introduced afterTabId and left the append in place. Before that the
client used terminal.create with no anchor, so both sides appended and agreed.
Rather than teach the client to re-derive the host's rule, both sides now call
one shared placeCreatedSessionTab, and the client captures a single afterTabId
for the request and the paint so they cannot drift apart again.
The host change is a pure refactor onto the shared helper; the 1260-test
runtime characterization suite is unchanged. The mobile route-parity hash pin
moves once because handleCreateTerminal's body changed - it is the only one of
the 12 extracted functions that differs.
48 lines
1.4 KiB
TypeScript
48 lines
1.4 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { placeCreatedSessionTab } from './session-tab-placement'
|
|
|
|
const created = { id: 'new' }
|
|
|
|
describe('placeCreatedSessionTab', () => {
|
|
it('inserts directly after the anchor', () => {
|
|
expect(
|
|
placeCreatedSessionTab([{ id: 'a' }, { id: 'b' }, { id: 'c' }], created, 'a').map((t) => t.id)
|
|
).toEqual(['a', 'new', 'b', 'c'])
|
|
})
|
|
|
|
it('appends when the anchor is the last tab', () => {
|
|
expect(
|
|
placeCreatedSessionTab([{ id: 'a' }, { id: 'b' }], created, 'b').map((t) => t.id)
|
|
).toEqual(['a', 'b', 'new'])
|
|
})
|
|
|
|
it('appends when the anchor is absent', () => {
|
|
expect(
|
|
placeCreatedSessionTab([{ id: 'a' }, { id: 'b' }], created, 'missing').map((t) => t.id)
|
|
).toEqual(['a', 'b', 'new'])
|
|
})
|
|
|
|
it('appends when no anchor is given', () => {
|
|
for (const anchor of [undefined, null, '']) {
|
|
expect(placeCreatedSessionTab([{ id: 'a' }], created, anchor).map((t) => t.id)).toEqual([
|
|
'a',
|
|
'new'
|
|
])
|
|
}
|
|
})
|
|
|
|
it('re-places a tab that is already in the list instead of duplicating it', () => {
|
|
expect(
|
|
placeCreatedSessionTab([{ id: 'a' }, { id: 'new' }, { id: 'b' }], created, 'b').map(
|
|
(t) => t.id
|
|
)
|
|
).toEqual(['a', 'b', 'new'])
|
|
})
|
|
|
|
it('does not mutate the input list', () => {
|
|
const tabs = [{ id: 'a' }, { id: 'b' }]
|
|
placeCreatedSessionTab(tabs, created, 'a')
|
|
expect(tabs.map((t) => t.id)).toEqual(['a', 'b'])
|
|
})
|
|
})
|