fix(native-chat): keep the owner-status read behind an in-flight attach

The handoff removal dropped the per-session queue from `handoffStatus`, so a
read landing mid-start reported the reservation (no owner) instead of the
settled chat owner, and shipped desktop clients blocked worktree activation on
it. The read is queued again, as it was before the removal.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Brennan Benson
2026-09-25 00:02:53 -07:00
co-authored by Claude
parent b50c57472e
commit 12efdefd1f
2 changed files with 33 additions and 5 deletions
@@ -639,6 +639,31 @@ describe('restart', () => {
})
})
it('answers the owner status of a starting chat once its start settles', async () => {
await attach()
await reboot(async () => ({ outcome: 'pid-absent' }))
await host.restoreReadableSessions()
const started = Promise.withResolvers<void>()
const release = Promise.withResolvers<void>()
const settled = acquire.getMockImplementation()
if (!settled) {
throw new Error('missing acquire implementation')
}
acquire.mockImplementationOnce(async (input) => {
started.resolve()
await release.promise
return settled(input)
})
const hold = host.hold(SESSION, 'surface-1')
await started.promise
const status = host.handoffStatus(SESSION)
release.resolve()
await hold
await expect(status).resolves.toMatchObject({ owner: 'native', stage: null })
})
it("keeps a session whose owner cannot be probed out of a live writer's hands", async () => {
await attach()
const held = store.getRecord(SESSION)?.lease.runtimeFence ?? 0
@@ -271,11 +271,14 @@ export class StructuredAgentSessionHost {
async handoffStatus(sessionId: string): Promise<SessionWire.AgentSessionHandoffStatus> {
this.requireSession(sessionId)
const record = this.deps.store.getRecord(sessionId)
if (!record) {
throw new Error('agent_session_identity_required')
}
return structuredAgentSessionOwnerStatus(record)
// Queued behind an in-flight attach, so a starting chat answers with its settled owner.
return this.serialize(sessionId, async () => {
const record = this.deps.store.getRecord(sessionId)
if (!record) {
throw new Error('agent_session_identity_required')
}
return structuredAgentSessionOwnerStatus(record)
})
}
history: StructuredAgentSessionBackgroundTaskChannel['history'] = (request) =>