-
Notifications
You must be signed in to change notification settings - Fork 0
fix(close): acknowledge document save before session snapshot #77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| import { describe, expect, it, vi } from 'vitest'; | ||
| import { handleCloseSaveRequest } from './close-save-handler'; | ||
|
|
||
| describe('handleCloseSaveRequest', () => { | ||
| it('reports document save before waiting for session snapshot persistence', async () => { | ||
| let releaseSnapshot!: () => void; | ||
| const snapshotFlush = new Promise<void>((resolve) => { releaseSnapshot = resolve; }); | ||
| const send = vi.fn(); | ||
| const request = handleCloseSaveRequest({ | ||
| requestId: 'save:1', | ||
| requestedRevision: 4, | ||
| save: async () => 4, | ||
| isDirty: () => false, | ||
| flushSessionSnapshot: () => snapshotFlush, | ||
| onSnapshotFlushError: vi.fn(), | ||
| send, | ||
| }); | ||
|
|
||
| await vi.waitFor(() => expect(send).toHaveBeenCalledWith('save:1', { saved: true, committedRevision: 4 })); | ||
| releaseSnapshot(); | ||
| await request; | ||
| }); | ||
|
|
||
| it('keeps a snapshot flush failure after a successful document ACK', async () => { | ||
| const send = vi.fn(); | ||
| const onSnapshotFlushError = vi.fn(); | ||
| await handleCloseSaveRequest({ | ||
| requestId: 'save:2', | ||
| requestedRevision: 4, | ||
| save: async () => 4, | ||
| isDirty: () => false, | ||
| flushSessionSnapshot: async () => { throw new Error('session write failed'); }, | ||
| onSnapshotFlushError, | ||
| send, | ||
| }); | ||
|
|
||
| expect(send).toHaveBeenCalledTimes(1); | ||
| expect(send).toHaveBeenCalledWith('save:2', { saved: true, committedRevision: 4 }); | ||
| expect(onSnapshotFlushError).toHaveBeenCalledOnce(); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| type CloseSaveResult = { | ||
| saved: boolean; | ||
| committedRevision: number | null; | ||
| }; | ||
|
|
||
| export type CloseSaveRequest = { | ||
| requestId: string; | ||
| requestedRevision: number; | ||
| save: () => Promise<number | null>; | ||
| isDirty: () => boolean; | ||
| flushSessionSnapshot?: () => Promise<void>; | ||
| onSnapshotFlushError?: (error: unknown) => void; | ||
| send: (requestId: string, result: CloseSaveResult) => void; | ||
| }; | ||
|
|
||
| /** | ||
| * Complete the authoritative document save handshake before doing best-effort | ||
| * session persistence. The main process can then finish the close transaction | ||
| * without waiting on the recovery snapshot write. | ||
| */ | ||
| export async function handleCloseSaveRequest({ | ||
| requestId, | ||
| requestedRevision, | ||
| save, | ||
| isDirty, | ||
| flushSessionSnapshot, | ||
| onSnapshotFlushError, | ||
| send, | ||
| }: CloseSaveRequest): Promise<void> { | ||
| let committedRevision: number | null; | ||
| try { | ||
| committedRevision = await save(); | ||
| } catch { | ||
| send(requestId, { saved: false, committedRevision: null }); | ||
| return; | ||
| } | ||
|
|
||
| const saved = committedRevision !== null && committedRevision >= requestedRevision; | ||
| send(requestId, { | ||
| saved, | ||
| committedRevision: saved ? committedRevision : null, | ||
| }); | ||
|
|
||
| if (!saved || isDirty() || !flushSessionSnapshot) return; | ||
| try { | ||
| await flushSessionSnapshot(); | ||
|
Comment on lines
+44
to
+46
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When session persistence is the slow or stalled operation this change is intended to tolerate, invoking AGENTS.md reference: AGENTS.md:L15-L15 Useful? React with 👍 / 👎. |
||
| } catch (error) { | ||
| onSnapshotFlushError?.(error); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reviewed commit records both author and committer as
Codex <codex@openai.com>, while this repository requires every commit to use the project820 GitHub noreply identity. Recreate the commit under the required identity before it is submitted.AGENTS.md reference: AGENTS.md:L9-L9
Useful? React with 👍 / 👎.