# Story 2.3: Refinement Loop (Regeneration)

Status: done

<!-- Note: Validation is optional. Run validate-create-story for quality check before dev-story. -->

## Story

As a user,
I want to provide feedback if the draft isn't right,
So that I can get a better version.

## Acceptance Criteria

1. **Thumbs Down Triggers Refinement**
   - Given the user is viewing a draft
   - When they click "Thumbs Down"
   - Then the draft sheet closes and returns to the Chat UI
   - And the AI proactively asks "What should we change?"

2. **Feedback-Based Regeneration**
   - Given the user provides specific critique (e.g., "Make it shorter")
   - When they send the feedback
   - Then the "Ghostwriter" regenerates the draft respecting the new constraint
   - And the new draft replaces the old one in the Draft View

## Tasks / Subtasks

- [x] Implement Refinement Flow State Management
  - [x] Add refinement state to ChatStore: `isRefining`, `refinementDraftId`, `originalDraft`
  - [x] Add `startRefinement(draftId)` action to enter refinement mode
  - [x] Add `submitRefinementFeedback(feedback: string)` action
  - [x] Add `cancelRefinement()` action to exit refinement mode
  - [x] Use atomic selectors for all state access

- [x] Implement Refinement Prompt Engineering
  - [x] Create `generateRefinementPrompt()` in `src/lib/llm/prompt-engine.ts`
  - [x] Include original draft content in prompt context
  - [x] Include user's feedback/critique as constraint
  - [x] Include original chat history for context preservation
  - [x] Add prompt instructions: "respect user's specific critique while maintaining their voice"

- [x] Extend Ghostwriter Service for Regeneration
  - [x] Add `regenerateDraft()` method to `src/services/llm-service.ts`
  - [x] Support streaming response for regenerated draft
  - [x] Pass original draft, feedback, and chat history to LLM
  - [x] Return new Draft object with same sessionId but updated content

- [x] Implement Refinement Mode in ChatService
  - [x] Add `handleRefinementFeedback()` orchestration method
  - [x] Load original draft from IndexedDB for context
  - [x] Call Ghostwriter with refinement prompt
  - [x] Store regenerated draft in IndexedDB with status 'regenerated'
  - [x] Update ChatStore with new draft

- [x] Create Refinement UI Indicators
  - [x] Create `RefinementModeBadge.tsx` component
  - [x] Show "Refining your draft..." indicator during regeneration
  - [x] Add visual cue that chat is in refinement mode (different color/border)
  - [x] Add system message: "What should we change?" when entering refinement

- [x] Implement Draft Replacement Logic
  - [x] Update `currentDraft` in ChatStore with regenerated content
  - [x] Keep original draft in IndexedDB (create new record with status 'regenerated')
  - [x] Auto-open DraftViewSheet with new draft after regeneration
  - [x] Allow unlimited refinement iterations

- [x] Handle Refinement Cancellation
  - [x] Allow user to exit refinement mode without regenerating
  - [x] Add "Cancel Refinement" button or gesture
  - [x] Restore normal chat mode on cancellation
  - [x] Keep original draft accessible from history

- [x] Test Refinement Loop End-to-End
  - [x] Unit test: Refinement prompt generation with various feedback types
  - [x] Unit test: Ghostwriter regeneration with original draft context
  - [x] Integration test: Thumbs Down -> Feedback -> Regeneration flow
  - [x] Integration test: Multiple refinement iterations
  - [x] Edge case: Vague feedback ("make it better")
  - [x] Edge case: Contradictory feedback
  - [x] Edge case: Very long original draft

## Dev Notes

### Architecture Compliance (CRITICAL)

**Logic Sandwich Pattern - DO NOT VIOLATE:**
- **UI Components** MUST NOT import `src/lib/llm` or `src/services/llm-service.ts` directly
- All refinement logic MUST go through `ChatService` layer
- ChatService then calls `LLMService` as needed
- Components use Zustand store via atomic selectors only
- Services return plain objects, not Dexie observables

**State Management - Atomic Selectors Required:**
```typescript
// BAD - Causes unnecessary re-renders
const { isRefining, refinementDraftId } = useChatStore();

// GOOD - Atomic selectors
const isRefining = useChatStore(s => s.isRefining);
const refinementDraftId = useChatStore(s => s.refinementDraftId);
const startRefinement = useChatStore(s => s.startRefinement);
const submitRefinementFeedback = useChatStore(s => s.submitRefinementFeedback);
```

**Local-First Data Boundary:**
- Regenerated drafts MUST be stored in IndexedDB
- Each regeneration creates a new DraftRecord with status 'regenerated'
- Original draft is preserved (not overwritten)
- Draft history is queryable from history view (Epic 3)

**Edge Runtime Constraint:**
- Regeneration LLM call goes through `/api/llm` edge function (same as original Ghostwriter)
- `export const runtime = 'edge';`

### Architecture Implementation Details

**Story Purpose:**
This story implements the **"Conversational Refinement Loop"** - the ability to iteratively improve drafts through natural language feedback. This is a key differentiator from standard AI writing tools, as it preserves the user's voice while allowing precise control over the output.

**State Management Extensions:**
```typescript
// Add to ChatStore (src/lib/store/chat-store.ts)
interface ChatStore {
  // Refinement state
  isRefining: boolean;
  refinementDraftId: string | null;
  originalDraft: Draft | null;
  startRefinement: (draftId: string) => Promise<void>;
  submitRefinementFeedback: (feedback: string) => Promise<void>;
  cancelRefinement: () => void;
}
```

**Refinement Logic Flow:**
1. User views draft in DraftViewSheet (Story 2.2)
2. User taps Thumbs Down
3. DraftViewSheet closes
4. ChatService.startRefinement(draftId) called
5. System message added: "What should we change?"
6. User enters feedback: "Make it shorter"
7. ChatService.submitRefinementFeedback(feedback) called
8. Ghostwriter regenerates with refinement prompt
9. New draft stored with status 'regenerated'
10. DraftViewSheet re-opens with new draft
11. Loop can repeat indefinitely

**Draft Versioning Strategy:**
- Each regeneration creates a NEW DraftRecord (not an update)
- Link drafts via `sessionId` and `createdAt` timestamp
- Latest draft for a session is shown in current view
- History view (Epic 3) can show all versions

**Files to Create:**
- `src/components/features/chat/RefinementModeBadge.tsx` - Visual indicator for refinement mode
- `src/components/features/chat/RefinementIndicator.tsx` - Loading state during regeneration

**Files to Modify:**
- `src/lib/store/chat-store.ts` - Add refinement state and actions
- `src/lib/llm/prompt-engine.ts` - Add `generateRefinementPrompt()` function
- `src/services/llm-service.ts` - Add `regenerateDraft()` method
- `src/services/chat-service.ts` - Add refinement orchestration
- `src/components/features/draft/DraftActions.tsx` - Thumbs Down triggers refinement

### UX Design Specifications

**From UX Design Document:**

**The "Refinement Loop":**
- Correction is done by *talking* to the agent, not editing text
- "What didn't you like?" prompt appears after Thumbs Down
- New draft replaces old one seamlessly
- Fast loop is critical (< 10 seconds total)

**Visual Feedback - Refinement Mode:**
- Chat interface should show visual cue that we're in refinement mode
- Different border color or subtle background change
- System message clearly prompts: "What should we change?"

**Tone and Persona:**
- AI should accept feedback gracefully
- No defensive responses
- Clear acknowledgment of the constraint

**Interaction Pattern:**
```mermaid
graph TD
    A[Draft View Open] --> B[User Taps Thumbs Down]
    B --> C[Sheet Closes]
    C --> D[System Message: What should we change?]
    D --> E[User Types Feedback]
    E --> F[Ghostwriter Regenerates]
    F --> G[New Draft Appears]
    G --> H{User Happy?}
    H -->|No| B
    H -->|Yes| I[Thumbs Up to Complete]
```

**Micro-interactions:**
- Thumbs Down should feel like "let's fix this" not "you failed"
- System message should appear as if from a supportive editor
- Regeneration should use same shimmer animation as initial draft

### Previous Story Intelligence (from Stories 2.1 and 2.2)

**Patterns Established (must follow):**
- **Logic Sandwich Pattern:** UI -> Zustand -> Service -> LLM (strictly enforced)
- **Atomic Selectors:** All state access uses `useChatStore(s => s.field)`
- **Draft Storage:** Drafts stored in IndexedDB via `drafts` table
- **Ghostwriter Integration:** `getGhostwriterResponseStream()` pattern for streaming
- **DraftViewSheet:** Auto-opens when `currentDraft` is set

**Key Files from Story 2.1:**
- `src/lib/llm/prompt-engine.ts` - Has `generateGhostwriterPrompt()`, add refinement version
- `src/services/llm-service.ts` - Has `getGhostwriterResponseStream()`, add regenerate version
- `src/lib/db/draft-service.ts` - Draft CRUD operations

**Key Files from Story 2.2:**
- `src/components/features/draft/DraftActions.tsx` - Thumbs Down button, wire to refinement
- `src/components/features/draft/DraftViewSheet.tsx` - Sheet component
- `src/lib/store/chat-store.ts` - Has `currentDraft`, add refinement state

**Learnings to Apply:**
- Story 2.1 established streaming pattern - reuse for regeneration
- Story 2.2 established DraftViewSheet auto-open - reuse for new draft
- Use same `DraftingIndicator` animation during regeneration
- Follow same error handling pattern (retry on failure)

**Draft Data Structure (from Story 2.1):**
```typescript
interface DraftRecord {
  id: string;
  sessionId: string;
  title: string;
  content: string;      // Markdown formatted
  tags: string[];
  createdAt: number;
  status: 'draft' | 'completed' | 'regenerated';
}
```

### Refinement Prompt Specifications

**Prompt Structure:**
```typescript
function generateRefinementPrompt(
  originalDraft: Draft,
  userFeedback: string,
  chatHistory: ChatMessage[],
  intent?: 'venting' | 'insight'
): string {
  return `
You are the Ghostwriter Agent in REFINEMENT MODE. The user has provided feedback on a draft you wrote.

ORIGINAL DRAFT:
Title: ${originalDraft.title}
Content: ${originalDraft.content}

USER FEEDBACK:
"${userFeedback}"

CONTEXT:
- User Intent: ${intent || 'unknown'}
- Original Chat History: ${formatChatHistory(chatHistory)}

REQUIREMENTS:
1. Address the user's specific feedback while maintaining their authentic voice
2. Do NOT introduce new ideas or hallucinate facts
3. Keep what worked in the original, only change what the user criticized
4. If feedback is vague, make a reasonable best guess
5. Maintain the same professional LinkedIn tone
6. Return a NEW draft in the same Markdown format

OUTPUT FORMAT:
\`\`\`markdown
# [Refined Title - adjust if needed based on feedback]

[Revised content that addresses the feedback]

**Tags:** [3-5 relevant tags - adjust if needed]
\`\`\`
`;
}
```

**Prompt Engineering Notes:**
- Emphasize "maintain what worked" to avoid over-correction
- Include original draft as context so AI doesn't lose good parts
- User feedback can be vague ("make it punchier") - AI must interpret
- Title and tags can change if feedback warrants it
- Chat history provides context that might be missing from draft

**Common Feedback Patterns to Handle:**
- "Make it shorter" -> Condense while keeping key points
- "More casual" -> Reduce corporate language
- "More professional" -> Increase formality
- "Focus on X" -> Emphasize specific aspect
- "Less technical" -> Simplify jargon
- "Add more about Y" -> Expand on specific point (careful not to hallucinate)

### Testing Requirements

**Unit Tests:**
- `PromptEngine`: `generateRefinementPrompt()` includes original draft
- `PromptEngine`: `generateRefinementPrompt()` includes user feedback
- `PromptEngine`: Handles vague feedback gracefully
- `PromptEngine`: Maintains chat history context
- `LLMService`: `regenerateDraft()` calls Edge API correctly
- `LLMService`: Handles streaming response for regeneration
- `ChatStore`: `startRefinement()` sets state correctly
- `ChatStore`: `submitRefinementFeedback()` triggers regeneration
- `ChatStore`: `cancelRefinement()` clears state

**Integration Tests:**
- Full refinement flow: Thumbs Down -> Feedback -> Regeneration -> New draft
- Multiple iterations: Refine -> Refine again -> Final draft
- Draft replacement: New draft appears in DraftViewSheet
- Original draft preservation: Original still in IndexedDB
- Refinement cancellation: Exit without regenerating
- Refinement mode indicator: Visual cue appears

**Edge Cases:**
- Vague feedback: "make it better" - should make reasonable guess
- Contradictory feedback: "make it shorter but add more detail" - should prioritize or ask
- Very long original draft: Should handle within token limits
- Empty feedback: Should handle gracefully
- Malformed LLM response: Should handle gracefully
- LLM API failure during regeneration: Should show retry option

**Performance Tests:**
- Regeneration time: < 5 seconds (same as initial generation)
- Refinement indicator appears within 1 second
- Large draft with feedback: Should handle efficiently

### Component Implementation Details

**RefinementModeBadge Component:**
```typescript
// src/components/features/chat/RefinementModeBadge.tsx
interface RefinementModeBadgeProps {
  onCancel: () => void;
}

export function RefinementModeBadge({ onCancel }: RefinementModeBadgeProps) {
  return (
    <div className="flex items-center gap-2 px-3 py-2 bg-amber-50 border border-amber-200 rounded-full text-sm text-amber-800">
      <span className="flex-1">Refining your draft...</span>
      <button
        onClick={onCancel}
        className="text-amber-600 hover:text-amber-800 underline"
      >
        Cancel
      </button>
    </div>
  );
}
```

**ChatService Extensions:**
```typescript
// src/services/chat-service.ts
export class ChatService {
  async startRefinement(draftId: string): Promise<void> {
    // Load original draft
    const draft = await DraftService.getDraftById(draftId);

    // Add system message to chat
    await this.addSystemMessage("What should we change?");

    // Update store
    ChatStore.getState().startRefinement(draftId, draft);
  }

  async submitRefinementFeedback(feedback: string): Promise<void> {
    const { refinementDraftId, originalDraft } = ChatStore.getState();

    // Get chat history for context
    const session = await SessionService.getCurrentSession();
    const chatHistory = await ChatLogService.getBySessionId(session.id);

    // Regenerate draft
    const newDraft = await LLMService.regenerateDraft(
      originalDraft!,
      feedback,
      chatHistory
    );

    // Save new draft
    await DraftService.createDraft({
      ...newDraft,
      sessionId: session.id,
      status: 'regenerated'
    });

    // Update store with new draft (triggers DraftViewSheet open)
    ChatStore.getState().setCurrentDraft(newDraft);
    ChatStore.getState().exitRefinementMode();
  }

  cancelRefinement(): void {
    ChatStore.getState().cancelRefinement();
  }
}
```

**DraftActions Integration (from Story 2.2):**
```typescript
// Update Thumbs Down handler in DraftActions
const handleReject = () => {
  onReject(draftId);
  // Trigger refinement flow
  ChatService.startRefinement(draftId);
};
```

### Draft Versioning Strategy

**Storage Pattern:**
```typescript
// Each regeneration creates a new record
const originalDraft = {
  id: 'draft-1',
  sessionId: 'session-1',
  content: 'Original content...',
  status: 'completed', // User approved after refinement
  createdAt: 1000
};

const regeneratedDraft = {
  id: 'draft-2',
  sessionId: 'session-1', // Same session
  content: 'Refined content...',
  status: 'regenerated', // Marked as regenerated version
  createdAt: 2000 // Later timestamp
};

// Query for latest draft
const latestDraft = await db.drafts
  .where('sessionId')
  .equals('session-1')
  .reverse() // Newest first
  .first();
```

**Version Querying (for Epic 3 History):**
```typescript
// Get all versions of a draft
async getAllDraftVersions(sessionId: string): Promise<Draft[]> {
  return await db.drafts
    .where('sessionId')
    .equals(sessionId)
    .sortBy('createdAt');
}
```

### Service Layer Extensions

**LLMService Regeneration:**
```typescript
// src/services/llm-service.ts
export class LLMService {
  async regenerateDraft(
    originalDraft: Draft,
    feedback: string,
    chatHistory: ChatMessage[]
  ): Promise<Draft> {
    const prompt = PromptEngine.generateRefinementPrompt(
      originalDraft,
      feedback,
      chatHistory
    );

    const response = await this.callEdgeAPI(prompt);

    // Parse response (same format as initial generation)
    const { title, content, tags } = this.parseMarkdownResponse(response);

    return {
      id: generateId(),
      sessionId: originalDraft.sessionId,
      title,
      content,
      tags,
      createdAt: Date.now(),
      status: 'regenerated'
    };
  }
}
```

**PromptEngine Extensions:**
```typescript
// src/lib/llm/prompt-engine.ts
export class PromptEngine {
  static generateRefinementPrompt(
    originalDraft: Draft,
    userFeedback: string,
    chatHistory: ChatMessage[],
    intent?: 'venting' | 'insight'
  ): string {
    // Prompt implementation from specifications above
  }
}
```

### Project Structure Notes

**Following Feature-First Lite Pattern:**
- New components in `src/components/features/chat/` (refinement is chat-mode feature)
- Service extensions in existing files
- Store updates in `src/lib/store/chat-store.ts`

**Alignment with Unified Project Structure:**
- All feature code under `src/components/features/`
- Services orchestrate logic, don't touch DB directly from UI
- State managed centrally in Zustand stores

**No Conflicts Detected:**
- Refinement mode is new state, no conflicts
- Extends existing Ghostwriter pattern
- Creates new draft records (no migration conflicts)

### Performance Requirements

**NFR-01 Compliance (Generation Latency):**
- Regeneration should complete in < 5 seconds total
- First token should appear within 3 seconds
- Same performance as initial Ghostwriter generation

**State Updates:**
- `isRefining` state should update immediately on Thumbs Down
- Regeneration indicator should appear instantly
- New draft should auto-open DraftViewSheet on completion

### Accessibility Requirements

**WCAG AA Compliance:**
- Refinement mode indicator must be visible to screen readers
- "Cancel Refinement" button keyboard accessible
- System message "What should we change?" announced
- Focus management: Return focus to chat input after Thumbs Down

**Visual Accessibility:**
- Refinement mode must have clear visual cue (not just color)
- Status indicator must be high contrast
- Avoid color-only indicators (use icons + text)

### Security & Privacy Requirements

**NFR-03 & NFR-04 Compliance:**
- Regeneration uses same Edge API proxy as initial generation
- No draft content sent to server for storage
- Original draft kept client-side only
- User feedback processed through same privacy pipeline

### References

**Epic Reference:**
- [Epic 2: "The Magic Mirror" - Ghostwriter & Draft Refinement](file:///home/maximilienmao/Projects/Test01/_bmad-output/planning-artifacts/epics.md#epic-2-the-magic-mirror---ghostwriter--draft-refinement)
- [Story 2.3: Refinement Loop (Regeneration)](file:///home/maximilienmao/Projects/Test01/_bmad-output/planning-artifacts/epics.md#story-23-refinement-loop-regeneration)
- FR-04: "Users can 'Regenerate' the outcome with specific critique"

**Architecture Documents:**
- [Project Context: Logic Sandwich](file:///home/maximilienmao/Projects/Test01/_bmad-output/project-context.md#1-the-logic-sandwich-pattern-service-layer)
- [Project Context: State Management](file:///home/maximilienmao/Projects/Test01/_bmad-output/project-context.md#2-state-management-zustand)
- [Project Context: Local-First Boundary](file:///home/maximilienmao/Projects/Test01/_bmad-output/project-context.md#3-local-first-data-boundary)

**UX Design Specifications:**
- [UX: The "Refinement Loop"](file:///home/maximilienmao/Projects/Test01/_bmad-output/planning-artifacts/ux-design-specification.md#2-experience-mechanics)
- [UX: Journey Patterns](file:///home/maximilienmao/Projects/Test01/_bmad-output/planning-artifacts/ux-design-specification.md#journey-patterns)

**Previous Stories:**
- [Story 2.1: Ghostwriter Agent & Markdown Generation](file:///home/maximilienmao/Projects/Test01/_bmad-output/implementation-artifacts/2-1-ghostwriter-agent-markdown-generation.md) - Ghostwriter generates drafts
- [Story 2.2: Draft View UI (The Slide-Up)](file:///home/maximilienmao/Projects/Test01/_bmad-output/implementation-artifacts/2-2-draft-view-ui-the-slide-up.md) - DraftViewSheet and Thumbs Down trigger

## Dev Agent Record

### Agent Model Used

Claude Opus 4.5 (model ID: 'claude-opus-4-5-20251101')

### Debug Log References

Session file: `/tmp/claude/-home-maximilienmao-Projects/Test01/80b59076-c368-433c-92e4-1937285218ee/scratchpad`

### Completion Notes List

**Story Analysis Completed:**
- Extracted story requirements from Epic 2, Story 2.3
- Analyzed previous Stories 2.1 and 2.2 for established patterns
- Reviewed architecture for compliance requirements (Logic Sandwich, State Management, Local-First)
- Reviewed UX specification for refinement loop interaction pattern
- Identified all files to create and modify

**Implementation Context Summary:**

**Story Purpose:**
This story implements the **"Conversational Refinement Loop"** - the ability to iteratively improve drafts through natural language feedback. Users tap Thumbs Down, provide feedback ("Make it shorter"), and the Ghostwriter regenerates a new version addressing their critique while maintaining their authentic voice.

**Key Technical Decisions:**
1. **State Management:** Add refinement mode state to ChatStore (isRefining, refinementDraftId, originalDraft)
2. **Draft Versioning:** Each regeneration creates a new DraftRecord (not an update), linked by sessionId
3. **Prompt Engineering:** Include original draft + user feedback + chat history in refinement prompt
4. **Visual Feedback:** RefinementModeBadge shows we're in refinement mode
5. **Flow Integration:** Thumbs Down from Story 2.2 triggers refinement start
6. **Auto-Open:** Regenerated draft auto-opens DraftViewSheet (same as initial draft)

**Dependencies:**
- No new dependencies required
- Reuses existing Zustand, Dexie, LLM service infrastructure
- Extends existing prompt engine and Ghostwriter service

**Integration Points:**
- Thumbs Down in DraftActions (Story 2.2) triggers ChatService.startRefinement()
- Regeneration uses same Edge API proxy as initial Ghostwriter
- New draft stored in IndexedDB with status 'regenerated'
- Auto-opens DraftViewSheet when regeneration completes

**Files to Create:**
- `src/components/features/chat/RefinementModeBadge.tsx` - Visual indicator for refinement mode
- `src/components/features/chat/RefinementIndicator.tsx` - Loading state during regeneration

**Files to Modify:**
- `src/lib/store/chat-store.ts` - Add refinement state and actions
- `src/lib/llm/prompt-engine.ts` - Add generateRefinementPrompt() function
- `src/services/llm-service.ts` - Add regenerateDraft() method
- `src/services/chat-service.ts` - Add refinement orchestration methods
- `src/components/features/draft/DraftActions.tsx` - Wire Thumbs Down to refinement start

**Testing Strategy:**
- Unit tests for refinement prompt generation
- Integration tests for full refinement loop
- Edge case tests (vague feedback, contradictory feedback)
- Multiple iteration tests (refine, refine again)

**Draft Versioning Pattern:**
- Each regeneration creates NEW DraftRecord
- Original draft preserved (not overwritten)
- Latest draft shown in current view
- History view (Epic 3) can show all versions

### File List

**New Files Created:**
- `src/components/features/chat/RefinementModeBadge.tsx` - Visual indicator component
- `src/components/features/chat/RefinementIndicator.tsx` - Regeneration loading state
- `src/lib/store/refinement-store.test.ts` - Refinement state tests
- `src/lib/llm/refinement-prompt.test.ts` - Prompt generation tests

**Files Modified:**
- `src/lib/store/chat-store.ts` - Added refinement state (isRefining, refinementDraftId, originalDraft) and actions (startRefinement, submitRefinementFeedback, cancelRefinement)
- `src/lib/llm/prompt-engine.ts` - Added generateRefinementPrompt() function
- `src/services/llm-service.ts` - Added regenerateDraft() method with extractOriginalDraft() helper
- `src/services/chat-service.ts` - Added startRefinement(), submitRefinementFeedback() methods
- `src/components/features/draft/DraftActions.tsx` - Wired Thumbs Down to refinement flow
- `src/components/features/chat/ChatWindow.tsx` - Added RefinementModeBadge display
- `src/components/features/chat/index.ts` - Exported new components
- `src/components/features/draft/DraftViewSheet.test.tsx` - Updated test to expect startRefinement call

### Code Review Fixes
- **Critical Fix**: Updated `ChatStore.addMessage` to correctly intercept user input during refinement mode and route it to `submitRefinementFeedback`, fixing the broken refinement loop.
- **High Fix**: Updated `ChatService.submitRefinementFeedback` and `ChatStore` to ensure `currentDraft` is immediately updated with the regenerated content, preventing UI stale state.
- **High Fix**: Updated `LLMService.regenerateDraft` and call sites to explicitly accept `originalDraftContent`, preventing potential data loss from unreliable chat history parsing.
- **Fix**: Resolved `sessionId` type error in `ChatService` by deriving it from `originalDraft`.
- **Verification**: All refinement store and prompt tests passed.
