From cf9a1f9077bfce0f5a1c5ee315c36b15c9a9fdd5 Mon Sep 17 00:00:00 2001 From: Kacper Date: Thu, 1 Jan 2026 18:41:25 +0100 Subject: [PATCH] fix(backlog-plan): use extractJsonWithArray and improve logging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Switch from extractJson to extractJsonWithArray for 'changes' field - Validates that 'changes' is an array, not just that it exists - Add debug logging for response length and preview on parse failure - Add debug logging when receiving result from Cursor provider - Matches pattern used by suggestions feature - Helps diagnose parsing issues with better error context 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- apps/server/src/routes/backlog-plan/generate-plan.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/server/src/routes/backlog-plan/generate-plan.ts b/apps/server/src/routes/backlog-plan/generate-plan.ts index 94a16b14..15302cbc 100644 --- a/apps/server/src/routes/backlog-plan/generate-plan.ts +++ b/apps/server/src/routes/backlog-plan/generate-plan.ts @@ -10,7 +10,7 @@ import type { Feature, BacklogPlanResult, BacklogChange, DependencyUpdate } from import { DEFAULT_PHASE_MODELS } from '@automaker/types'; import { FeatureLoader } from '../../services/feature-loader.js'; import { ProviderFactory } from '../../providers/provider-factory.js'; -import { extractJson } from '../../lib/json-extractor.js'; +import { extractJsonWithArray } from '../../lib/json-extractor.js'; import { logger, setRunningState, getErrorMessage } from './common.js'; import type { SettingsService } from '../../services/settings-service.js'; import { getAutoLoadClaudeMdSetting, getPromptCustomization } from '../../lib/settings-helpers.js'; @@ -45,17 +45,19 @@ function formatFeaturesForPrompt(features: Feature[]): string { */ function parsePlanResponse(response: string): BacklogPlanResult { // Use shared JSON extraction utility for robust parsing - const parsed = extractJson(response, { + // extractJsonWithArray validates that 'changes' exists AND is an array + const parsed = extractJsonWithArray(response, 'changes', { logger, - requiredKey: 'changes', }); if (parsed) { return parsed; } - // If parsing fails, return an empty result + // If parsing fails, log details and return an empty result logger.warn('[BacklogPlan] Failed to parse AI response as JSON'); + logger.debug('[BacklogPlan] Response text length:', response.length); + logger.debug('[BacklogPlan] Response preview:', response.slice(0, 500)); return { changes: [], summary: 'Failed to parse AI response', @@ -149,6 +151,7 @@ export async function generateBacklogPlan( } else if (msg.type === 'result' && msg.subtype === 'success' && msg.result) { // Use result if it's a final accumulated message (from Cursor provider) if (msg.result.length > responseText.length) { + logger.debug('[BacklogPlan] Received result from Cursor, length:', msg.result.length); responseText = msg.result; } }