From d727a812e64abf01326f811ba35ca1079c3d832f Mon Sep 17 00:00:00 2001 From: Lauren ten Hoor Date: Tue, 10 Feb 2026 08:34:03 +0800 Subject: [PATCH 1/3] fix: add explicit worker state update in task_pickup after dispatch (#23) Adds defense-in-depth by explicitly calling activateWorker() in task_pickup.ts after dispatchTask() returns. This ensures the worker state (active, issueId, model, sessionKey, startTime) is properly set in projects.json even if dispatchTask's internal state update encounters issues. The redundant update: - Sets active=true, issueId, and model for both spawn and reuse cases - Sets sessionKey and startTime only on new spawns (not on session reuse) - Provides fallback if race conditions or I/O errors affect dispatch.ts Fixes #23 --- lib/tools/task-pickup.ts | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/lib/tools/task-pickup.ts b/lib/tools/task-pickup.ts index 02468e7..7143e17 100644 --- a/lib/tools/task-pickup.ts +++ b/lib/tools/task-pickup.ts @@ -17,7 +17,7 @@ import { dispatchTask } from "../dispatch.js"; import { type Issue, type StateLabel } from "../task-managers/task-manager.js"; import { createProvider } from "../task-managers/index.js"; import { selectModel } from "../model-selector.js"; -import { getProject, getWorker, readProjects } from "../projects.js"; +import { activateWorker, getProject, getWorker, readProjects } from "../projects.js"; import type { ToolContext } from "../types.js"; import { detectContext, generateGuardrails } from "../context-guard.js"; import { isDevTier, isTier, type Tier } from "../tiers.js"; @@ -313,6 +313,27 @@ export function createTaskPickupTool(api: OpenClawPluginApi) { pluginConfig, }); + // 8b. Explicitly update worker state in projects.json + // Defense in depth: ensure state is set even if dispatchTask had issues + const now = new Date().toISOString(); + const stateUpdateParams: { + issueId: string; + model: string; + sessionKey?: string; + startTime?: string; + } = { + issueId: String(issue.iid), + model: modelAlias, + }; + + // Only set sessionKey and startTime on new spawn (not on reuse) + if (dispatchResult.sessionAction === "spawn") { + stateUpdateParams.sessionKey = dispatchResult.sessionKey; + stateUpdateParams.startTime = now; + } + + await activateWorker(workspaceDir, groupId, role, stateUpdateParams); + // 9. Send notification to project group const notifyConfig = getNotificationConfig(pluginConfig); await notify( From 31481d4ae2e916048e7c03707708fe9cfc746099 Mon Sep 17 00:00:00 2001 From: Lauren ten Hoor Date: Tue, 10 Feb 2026 08:58:01 +0800 Subject: [PATCH 2/3] Revert "fix: add explicit worker state update in task_pickup after dispatch (#23)" This reverts commit d727a812e64abf01326f811ba35ca1079c3d832f. --- lib/tools/task-pickup.ts | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/lib/tools/task-pickup.ts b/lib/tools/task-pickup.ts index 7143e17..02468e7 100644 --- a/lib/tools/task-pickup.ts +++ b/lib/tools/task-pickup.ts @@ -17,7 +17,7 @@ import { dispatchTask } from "../dispatch.js"; import { type Issue, type StateLabel } from "../task-managers/task-manager.js"; import { createProvider } from "../task-managers/index.js"; import { selectModel } from "../model-selector.js"; -import { activateWorker, getProject, getWorker, readProjects } from "../projects.js"; +import { getProject, getWorker, readProjects } from "../projects.js"; import type { ToolContext } from "../types.js"; import { detectContext, generateGuardrails } from "../context-guard.js"; import { isDevTier, isTier, type Tier } from "../tiers.js"; @@ -313,27 +313,6 @@ export function createTaskPickupTool(api: OpenClawPluginApi) { pluginConfig, }); - // 8b. Explicitly update worker state in projects.json - // Defense in depth: ensure state is set even if dispatchTask had issues - const now = new Date().toISOString(); - const stateUpdateParams: { - issueId: string; - model: string; - sessionKey?: string; - startTime?: string; - } = { - issueId: String(issue.iid), - model: modelAlias, - }; - - // Only set sessionKey and startTime on new spawn (not on reuse) - if (dispatchResult.sessionAction === "spawn") { - stateUpdateParams.sessionKey = dispatchResult.sessionKey; - stateUpdateParams.startTime = now; - } - - await activateWorker(workspaceDir, groupId, role, stateUpdateParams); - // 9. Send notification to project group const notifyConfig = getNotificationConfig(pluginConfig); await notify( From 4663fa6fec5601708a1fbe03e23c338037402e69 Mon Sep 17 00:00:00 2001 From: Lauren ten Hoor Date: Tue, 10 Feb 2026 09:03:19 +0800 Subject: [PATCH 3/3] fix: remove GitHub auto-closing keywords from worker templates (#24) - Added explicit warning to DEFAULT_DEV_INSTRUCTIONS - Added warning to AGENTS_MD_TEMPLATE conventions section - Workers instructed to use 'As described in issue #X' instead of 'Closes #X' - Prevents GitHub/GitLab from auto-closing issues before QA validation --- lib/templates.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/templates.ts b/lib/templates.ts index cdfe59a..53b06fc 100644 --- a/lib/templates.ts +++ b/lib/templates.ts @@ -8,6 +8,7 @@ export const DEFAULT_DEV_INSTRUCTIONS = `# DEV Worker Instructions - Work in a git worktree (never switch branches in the main repo) - Run tests before completing - Create an MR/PR to the base branch and merge it +- **IMPORTANT:** Do NOT use closing keywords in PR/MR descriptions (no "Closes #X", "Fixes #X", "Resolves #X"). Instead use "As described in issue #X" or "Addresses issue #X". DevClaw manages issue state via task_complete - auto-closing bypasses QA validation. - Clean up the worktree after merging - When done, call task_complete with role "dev", result "done", and a brief summary - If you discover unrelated bugs, call task_create to file them @@ -41,6 +42,7 @@ Skip the orchestrator section. Follow your task message and role instructions (a - Branch naming: \`feature/-\` or \`fix/-\` - **DEV always works in a git worktree** (never switch branches in the main repo) - **DEV must merge to base branch** before announcing completion +- **Do NOT use closing keywords in PR/MR descriptions** (no "Closes #X", "Fixes #X", "Resolves #X"). Instead use "As described in issue #X" or "Addresses issue #X". DevClaw manages issue state via task_complete — auto-closing bypasses QA validation. - **QA tests on the deployed version** and inspects code on the base branch - Always run tests before completing