Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions packages/orchestrator/src/service.test.ts
Comment thread
hojinzs marked this conversation as resolved.
Comment thread
hojinzs marked this conversation as resolved.
Comment thread
hojinzs marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -1905,10 +1905,12 @@ describe("OrchestratorService", () => {
pid: 4101,
unref: vi.fn(),
});
const isProcessRunning = vi.fn().mockReturnValue(false);
const currentTime = new Date("2026-03-08T00:00:00.000Z");
const service = new OrchestratorService(store, projectConfig, {
fetchImpl: vi.fn().mockResolvedValue(createTrackerResponse(repository)),
spawnImpl: spawnImpl as never,
isProcessRunning,
now: () => currentTime,
});

Expand Down Expand Up @@ -1945,6 +1947,7 @@ describe("OrchestratorService", () => {
)
).resolves.toContain(`"workspaceKey": "${workspaceKey}"`);
expect(spawnImpl).toHaveBeenCalledTimes(1);
expect(isProcessRunning).toHaveBeenCalledWith(4101);
Comment thread
hojinzs marked this conversation as resolved.
expect((await store.loadAllRuns())[0]?.trackerItemId).toBe("item-1");
expect(spawnImpl).toHaveBeenCalledWith(
"bash",
Expand Down Expand Up @@ -3720,6 +3723,7 @@ Retry inconclusive work.
const stderr = {
write: vi.fn().mockReturnValue(true),
};
const isProcessRunning = vi.fn().mockReturnValue(false);

const service = new OrchestratorService(store, projectConfig, {
fetchImpl: vi
Expand All @@ -3728,6 +3732,7 @@ Retry inconclusive work.
createTrackerResponseWithState(repository, "Todo")
) as never,
spawnImpl: vi.fn().mockReturnValue(worker) as never,
isProcessRunning,
now: () => new Date("2026-03-08T00:00:00.000Z"),
stderr,
logLevel: "verbose",
Expand Down Expand Up @@ -3755,6 +3760,7 @@ Retry inconclusive work.
`[retry-scheduled] ${runId} kind=continuation attempt=1 nextAt=2026-03-08T00:00:01.000Z\n`
);
expect(output).toContain(`[run-completed] ${runId} status=retrying\n`);
expect(isProcessRunning).toHaveBeenCalledWith(4102);
});

it("invokes onTick with the reconciliation snapshot when run() completes a tick", async () => {
Expand Down Expand Up @@ -7296,6 +7302,7 @@ Prefer focused changes.
await store.saveProjectConfig(projectConfig);

const workers: EventEmitter[] = [];
const isProcessRunning = vi.fn().mockReturnValue(false);
const spawnImpl = vi.fn().mockImplementation(() => {
const worker = new EventEmitter() as EventEmitter & {
pid: number;
Expand Down Expand Up @@ -7323,6 +7330,7 @@ Prefer focused changes.
return createTrackerResponseWithState(repository, "Ready") as Response;
}) as never,
spawnImpl: spawnImpl as never,
isProcessRunning,
now: () => now,
});

Expand All @@ -7339,6 +7347,7 @@ Prefer focused changes.
expect(retryWorkerEnv?.SYMPHONY_RENDERED_PROMPT).toContain(
"retry_attempt=1"
);
expect(isProcessRunning).toHaveBeenCalledWith(4310);

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 해소 확인 — 1라운드에서 재현했던 실패가 사라졌습니다.

동일한 시뮬레이션(vitest.setup 에서 process.kill(pid, 0) 을 이 파일의 pid 리터럴 전체에 대해 성공시킴, 검증 후 원복)을 다시 돌린 결과입니다.

대상 service.test.ts 결과
base a77cc34 4 failed / 189 passed
PR head 516f7a63 193 passed (0 failed)

base 에서 깨진 4건이 정확히 이 PR 이 손댄 4건(이슈 명시 2건 + P1 + P2)과 일치합니다. 이 테스트도 그중 하나였고 이제 통과합니다.

worker.pid = 4310 + workers.length 로 워커가 여러 개 생기는데 첫 워커(4310)만 단언한 것도 적절합니다 — 재시도 판정이 걸리는 지점이 첫 워커의 종료이므로 이 단언이 주입 seam 을 정확히 가리킵니다.


Generated by Claude Code

});

it("renders a queued failure retry attempt during ordinary dispatch", async () => {
Expand Down Expand Up @@ -15802,12 +15811,14 @@ Prefer focused changes.
nextRetryAt: null,
});

const isProcessRunning = vi.fn().mockReturnValue(false);
const service = new OrchestratorService(store, projectConfig, {
fetchImpl: vi.fn().mockResolvedValue(createEmptyTrackerResponse()),
spawnImpl: vi.fn().mockReturnValue({
pid: 4202,
unref: vi.fn(),
}) as never,
isProcessRunning,
now: () => new Date("2026-03-08T00:00:00.000Z"),
});

Expand All @@ -15824,6 +15835,7 @@ Prefer focused changes.

expect(workspacePathFromHook).toBe(expectedWorkspacePath);
expect(repositoryPathFromHook).toBe(repository.path);
expect(isProcessRunning).toHaveBeenCalledWith(999999);

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 해소 확인 + 같은 부류의 잔존 노출면 1건 (이 PR 범위 밖, 별도 이슈 제안 — nit)

영속 processId 쪽도 닫혔습니다. 위 시뮬레이션에서 base 는 이 테스트가 ENOENT: .after_run_workspace_path 로 깨졌고 PR head 는 통과합니다.

추가로 orchestrator 패키지 전체를 같은 방식으로(패키지 내 테스트의 pid 리터럴 78개 전부 생존 처리) 돌려봤습니다.

범위 결과
orchestrator 14개 파일 전체, 가짜 pid 전부 생존 361 passed (0 failed)

dispatch.test.ts, recovery 계열 모두 깨끗합니다. #762 의 "동일 패턴을 쓰는 다른 테스트도 점검" 기준은 이걸로 충족된 것으로 봅니다.

다만 패키지 밖에 같은 부류가 하나 남아 있어 기록만 남깁니다. packages/cli/src/commands/lifecycle.test.ts:585processId: 999_999 가 여기와 완전히 동일한 패턴이고, recover --dry-run 이 실제 프로세스 테이블을 조회합니다.

FAIL  src/commands/lifecycle.test.ts > reports recoverable runs without invoking recovery in dry-run mode
AssertionError: expected false to be true
 ❯ src/commands/lifecycle.test.ts:611:7

(cli 패키지 pid 리터럴 생존 시뮬레이션: 1 failed / 590 passed. pid 999999 가 살아 있으면 stale run 이 recoverable 로 잡히지 않아 실패합니다.)

이 PR 에서 고치실 필요 없습니다. main 에 이미 있던 것이고 #762 의 명시 범위(orchestrator)도 아닙니다. pnpm test 전체를 게이트로 쓰는 로컬 에이전트 파이프라인 관점에서만 남은 구멍이라 별도 이슈로 올려두겠습니다.


Generated by Claude Code

});
});

Expand Down
Loading