Repository navigation
feat(checkpoints): per-write checkpoints, task-start baseline, and perWriteCheckpoints setting (B1, #1375) #1404
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
Open
easonLiangWorldedtech
wants to merge
37
commits into
Zoo-Code-Org:main
Choose a base branch
from
easonLiangWorldedtech:feat/per-write-checkpoints-b1
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
37 commits
Select commit
Hold shift + click to select a range
abfbe7f
feat(checkpoints): per-write checkpoints, task-start baseline, and pe…
easonliang28 b98f159
fix(fws): export the webview initializer and test the pre-hydration c…
easonliang28 abc10b4
chore(ci): empty commit — re-trigger CI and the CodeRabbit current-he…
easonliang28 0ea153d
Merge commit '0d937c050810ebc305b34368bf6d6ae8c1f89966' into feat/per…
easonliang28 cb657cb
Merge remote-tracking branch 'upstream/main' into feat/per-write-chec…
easonliang28 92ceb90
Merge remote-tracking branch 'upstream/main' into feat/per-write-chec…
23e9451
test(visual): regenerate electron chat-dark sidebar reference for #1404
b01a334
Merge upstream/main (9c069e94ef) into feat/per-write-checkpoints-b1
easonliang28 c07bea3
fix(checkpoints): skip task-start baseline on history resume
easonliang28 93e3640
fix(checkpoints): skip baseline on aborted task; share default constant
easonliang28 faf3f9d
fix(checkpoints): recheck cancellation after the baseline state lookup
easonliang28 fb57670
fix(checkpoints): await write-path checkpoint saves before state handoff
easonliang28 cae09fb
test(checkpoints): pin one-checkpoint-per-patch for multi-file patches
easonliang28 c6a23c5
fix(tools): defer the queued-message handoff until the patch checkpoi…
easonliang28 484d5cf
fix(task): never dequeue queued messages for an aborted task
easonliang28 0310c99
test(tools): pin the partial-failure handoff semantics of the patch c…
easonliang28 a83a105
chore: remove carried-over Stryker suppression directives from touche…
easonliang28 d21a437
test: strengthen the early-return handoff assertions
easonliang28 dd4802d
Merge upstream/main (tool-call state scoping) and adapt execute spec …
easonliang28 6666de5
style: apply Prettier formatting to callback fixture edits
easonliang28 3391528
test: assert the in-place update checkpoint contract
easonliang28 6f00e59
fix(apply-patch): fail moves when source deletion fails; checkpoint p…
easonliang28 e6e69fc
Merge upstream/main into b1 (upstream refresh; e2e screenshot conflic…
easonliang28 20af1c7
fix(tools): checkpoint retained writes before handoff after a handler…
easonliang28 a0d292e
fix(task): task-start checkpoint baseline errors no longer abort task…
easonliang28 8045ab0
Merge remote-tracking branch 'upstream/main' into feat/per-write-chec…
easonliang28 8865c4a
fix(checkpoints): restore a clobbered move destination when source de…
easonliang28 911ae24
fix(checkpoints): harden task-start baseline and service init per review
easonliang28 377c082
fix(task): bound the task-start baseline save; report a failed move r…
da46574
Merge remote-tracking branch 'upstream/main' into feat/per-write-chec…
easonLiangWorldedtech b6d8698
fix(tools): make the apply_patch move transactional with atomic stagi…
easonLiangWorldedtech 4b44f10
fix(tools): preserve destination identity and permissions in the atom…
easonLiangWorldedtech 5a32d91
fix(checkpoints): serialize per-task checkpoint saves
easonLiangWorldedtech 2e66db5
fix(tools): keep staging owner-only and make partial patch mutations …
easonLiangWorldedtech c585b1f
style: apply prettier formatting to the staging and mutation-tracking…
easonLiangWorldedtech c6bcc62
fix(tools): track committed mutations outside the handler-return boun…
easonLiangWorldedtech e2417cb
chore: re-trigger CI after the e2e restart-phase timeout
easonLiangWorldedtech File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
126 changes: 126 additions & 0 deletions
126
src/core/checkpoints/__tests__/getCheckpointService.spec.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| import { beforeEach, describe, expect, it, vi } from "vitest" | ||
|
|
||
| import type { Task } from "../../task/Task" | ||
| import { RepoPerTaskCheckpointService } from "../../../services/checkpoints" | ||
| import { checkGitInstalled } from "../../../utils/git" | ||
| import { getCheckpointService } from "../index" | ||
|
|
||
| vi.mock("../../../services/checkpoints", () => ({ | ||
| RepoPerTaskCheckpointService: { create: vi.fn() }, | ||
| })) | ||
|
|
||
| vi.mock("../../../utils/git", () => ({ | ||
| checkGitInstalled: vi.fn(), | ||
| })) | ||
|
|
||
| vi.mock("../../../utils/path", () => ({ | ||
| getWorkspacePath: vi.fn(() => "/workspace"), | ||
| })) | ||
|
|
||
| vi.mock("../../../i18n", () => ({ | ||
| t: (key: string) => key, | ||
| })) | ||
|
|
||
| /** | ||
| * Structural service double: getCheckpointService only registers listeners, | ||
| * awaits initShadowGit, and reads isInitialized. The double assertion at the | ||
| * create() call sites is confined to this file (AGENTS.md last-resort cast): | ||
| * the real class carries a Git handle and event surface the test never | ||
| * exercises. | ||
| */ | ||
| function serviceDouble(initShadowGitImpl: () => Promise<void>) { | ||
| const listeners = new Map<string, (...args: unknown[]) => void>() | ||
| let initialized = false | ||
| const svc = { | ||
| on: vi.fn((event: string, cb: (...args: unknown[]) => void) => { | ||
| listeners.set(event, cb) | ||
| }), | ||
| initShadowGit: vi.fn(() => initShadowGitImpl()), | ||
| get isInitialized() { | ||
| return initialized | ||
| }, | ||
| completeInit: () => { | ||
| initialized = true | ||
| listeners.get("initialize")?.() | ||
| }, | ||
| } | ||
| return svc | ||
| } | ||
|
|
||
| function makeTask(): Task { | ||
| return { | ||
| taskId: "task-init", | ||
| cwd: "/workspace", | ||
| enableCheckpoints: true, | ||
| checkpointService: undefined, | ||
| checkpointServiceInitializing: false, | ||
| checkpointTimeout: 1, | ||
| providerRef: { | ||
| deref: vi.fn().mockReturnValue({ | ||
| context: { globalStorageUri: { fsPath: "/tmp/b3-init-storage" } }, | ||
| postMessageToWebview: vi.fn(), | ||
| log: vi.fn(), | ||
| }), | ||
| }, | ||
| say: vi.fn().mockResolvedValue(undefined), | ||
| } as unknown as Task | ||
| } | ||
|
|
||
| describe("getCheckpointService initialization failures", () => { | ||
| beforeEach(() => { | ||
| vi.mocked(checkGitInstalled).mockReset() | ||
| vi.mocked(RepoPerTaskCheckpointService.create).mockReset() | ||
| }) | ||
|
|
||
| it("does not store a service whose shadow-git initialization failed", async () => { | ||
| vi.mocked(checkGitInstalled).mockResolvedValue(true) | ||
| const failing = serviceDouble(async () => { | ||
| throw new Error("shadow git init exploded") | ||
| }) | ||
| vi.mocked(RepoPerTaskCheckpointService.create).mockReturnValue( | ||
| failing as unknown as RepoPerTaskCheckpointService, | ||
| ) | ||
|
|
||
| const task = makeTask() | ||
| const service = await getCheckpointService(task) | ||
|
|
||
| // The failed service must not be stored: a stored uninitialized handle | ||
| // would be returned by the fast path to every later save, and the | ||
| // initializing flag must not strand later lookups in a wait for an | ||
| // initialization that already died. | ||
| expect(service).toBeUndefined() | ||
| expect(task.checkpointService).toBeUndefined() | ||
| expect(task.checkpointServiceInitializing).toBe(false) | ||
| expect(task.enableCheckpoints).toBe(false) | ||
| }) | ||
|
|
||
| it("does not store a service when Git is not installed", async () => { | ||
| vi.mocked(checkGitInstalled).mockResolvedValue(false) | ||
| const svc = serviceDouble(async () => {}) | ||
| vi.mocked(RepoPerTaskCheckpointService.create).mockReturnValue(svc as unknown as RepoPerTaskCheckpointService) | ||
|
|
||
| const task = makeTask() | ||
| const service = await getCheckpointService(task) | ||
|
|
||
| expect(service).toBeUndefined() | ||
| expect(task.checkpointService).toBeUndefined() | ||
| expect(task.checkpointServiceInitializing).toBe(false) | ||
| expect(task.enableCheckpoints).toBe(false) | ||
| }) | ||
|
|
||
| it("stores an initialized service on the success path", async () => { | ||
| vi.mocked(checkGitInstalled).mockResolvedValue(true) | ||
| const svc = serviceDouble(async () => { | ||
| svc.completeInit() | ||
| }) | ||
| vi.mocked(RepoPerTaskCheckpointService.create).mockReturnValue(svc as unknown as RepoPerTaskCheckpointService) | ||
|
|
||
| const task = makeTask() | ||
| const service = await getCheckpointService(task) | ||
|
|
||
| expect(service).toBe(svc) | ||
| expect(task.checkpointService).toBe(svc) | ||
| expect(task.checkpointServiceInitializing).toBe(false) | ||
| expect(task.enableCheckpoints).toBe(true) | ||
| }) | ||
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.