MoonshotAI / MoonshotAI/kimi-code

Background tasks marked "lost" without liveness check; resume spawns duplicate concurrent workers

Open
#1,924 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
7.5k
Forks
1.2k
Avg merge
11h 53m
Merged PRs (30d)
350

Description

Summary

When a kimi-code process with live background tasks is still running and a second process resumes the same session, markLoadedTasksLost marks the first process's non-terminal tasks as lostwithout any liveness probe, even though the task's PID is persisted on disk. The resume_hint returned to the model then explicitly instructs Agent(resume=agent_id) on task.lost, spawning a second concurrent worker on the same task while the first is still alive.

We hit this in production: two subagent instances ran concurrently for ~65 minutes, each editing the same file, each reporting "another session is modifying this file" — they were seeing each other. Both eventually completed; the task record had marked one of them lost while it was demonstrably alive.

Evidence (all paths verified against current master)

  1. packages/agent-core-v2/src/agent/task/taskService.ts:854-869markLoadedTasksLost iterates ghost tasks and marks every non-terminal one as lost and writes it back to disk. There is no process.kill(pid, 0)-style probe anywhere in this path.
  2. packages/agent-core-v2/src/agent/task/persist.ts:236,276 — the persisted task record already contains pid (LegacyPersistedTask.pid, mapped in toProcessTaskInfo), so the material for a liveness check is on disk, unused.
  3. packages/agent-core-v2/src/session/subagent/tools/agent.ts:481resume_hint lists task.lost as a recovery case and tells the model to call Agent(resume=agent_id), which makes duplicate workers a scripted outcome rather than an accident.
  4. There is no per-session cross-process lock, so two processes resuming the same session (e.g. a supervisor that spawns one CLI process per message with --resume) race: the live one's tasks get marked lost, and the task JSON itself is last-writer-wins between the two processes.

This is the same "killed but not reaped" family as #1882 (torn wire.jsonl after SIGKILL), one layer up in the stack.

Suggested fixes (in order of effort)

  1. Probe before marking lost (small): in markLoadedTasksLost, for kind === 'process' ghosts, run process.kill(pid, 0). If the process is alive, keep the task running and skip the lost notification. A ready-made probe pattern exists in apps/kap-server/src/lock.ts (PID + liveness check for instance locks).
  2. Fix the guidance (trivial): change resume_hint to state that lost does not mean the worker is dead, and that the caller should verify the old instance is gone before resuming.
  3. Per-session cross-process lock (design-level): owner PID + heartbeat, reusing the kap-server/src/lock.ts pattern. reconcile() skips lost-marking while the lock owner is alive. This also covers agent-kind tasks, which have no PID to probe (same-process loops).

We'd be happy to contribute (1) as a PR if the direction sounds right.

Environment

  • kimi-code 0.27.0, agent-core-v2
  • Linux, supervisor spawning one CLI process per message with --resume (cc-connect)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with markLoadedTasksLost in packages/agent-core-v2/src/agent/task/taskService.ts and compare the PID liveness pattern in apps/kap-server/src/lock.ts. Check the persisted PID mapping in packages/agent-core-v2/src/agent/task/persist.ts and the recovery wording in packages/agent-core-v2/src/session/subagent/tools/agent.ts. Done means live process tasks are not marked lost and the resume guidance no longer treats lost as proof that a worker is dead.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
cli
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.