Feature: Plan Service As a developer I want to manage plans So that I can generate and apply code changes Scenario: Create a new plan with prompt Given I have a plan service When I create a plan with prompt "Add error handling" Then the plan should be created And the plan prompt should be "Add error handling" And the plan should be the current plan Scenario: Create empty plan with name Given I have a plan service When I create an empty plan named "feature-x" Then the plan should be created And the plan name should be "feature-x" And the plan prompt should be empty Scenario: Build a plan to generate changes Given I have a plan service And I have created a plan with "Generate example code" When I build the plan Then changes should be generated And the changes should include file operations Scenario: Build plan uses actor selection Given I have a plan service with stub provider registry And I have created a plan with "Generate example code" When I build the plan with actor "anthropic/claude-dev" Then changes should be generated And the stub provider registry should record provider "anthropic" and model "claude-dev" Scenario: Build plan fails when no provider configured Given I have a plan service without providers configured And I have created a plan with "Generate example code" When I try to build the plan Then a PlanError should be raised with message "No AI provider configured" And the PlanError details should include provider diagnostics Scenario: Apply generated changes Given I have a plan service And I have created and built a plan When I apply the changes Then the changes should be applied And files should be created or modified Scenario: List all plans Given I have a plan service And I have created multiple plans When I list all plans Then I should see all created plans And each plan should have a name and status Scenario: Switch between plans Given I have a plan service And I have created plan "plan-a" And I have created plan "plan-b" When I switch to plan "plan-a" Then "plan-a" should be the current service plan And "plan-b" should not be current Scenario: Continue adding to existing plan Given I have a plan service And I have created a plan with "Initial instructions" When I add "Additional instructions" to the plan Then the plan should contain both instructions Scenario: Auto-debug build uses empty context when plan ID disappears Given I have a temporary test directory for plan service And I configured an auto-debug plan with a disappearing plan ID When I run auto-debug build with missing plan context Then the auto-debug build should fall back to an empty context Scenario: Apply changes moves files to absolute destinations Given I have a temporary test directory for plan service And I have a Unit of Work instance for plan testing And I have a PlanService instance And I have a saved project with current plan And the plan has a pending MOVE change to an absolute path When I apply the plan changes Then the absolute destination should exist and the source should be removed Scenario: Stream plan generation and persist usage Given I have a plan service with a streaming stub provider When I stream plan generation with prompt "Streamed instructions" Then the streaming events should include nodes "load_context, analyze_requirements, generate_plan, validate, __end__" And the streamed plan should persist token count 321 Scenario: Stream plan generation fails when provider never completes Given I have a plan service with an incomplete streaming provider When I try to stream plan generation with prompt "Incomplete stream" Then a PlanError should be raised with message "Provider streaming ended before completion" Scenario: Stream plan generation coerces dict payloads Given I have a plan service with a dict streaming provider When I stream plan generation with prompt "Dict payload" Then the streaming events should include nodes "generate_plan, __end__" And the streamed plan should persist token count 0 Scenario: Stream plan generation surfaces provider error strings Given I have a plan service with a string error streaming provider When I try to stream plan generation with prompt "String error" Then the streaming failure events should include an error with message "stub failure" And a PlanError should be raised with message "stub failure" Scenario: Stream plan generation rejects non-list change payloads Given I have a plan service with a non-list change streaming provider When I try to stream plan generation with prompt "Non list payload" Then a PlanError should be raised with message "Provider stream returned an invalid change payload" Scenario: Stream plan generation rejects invalid change entries Given I have a plan service with an invalid change entry streaming provider When I try to stream plan generation with prompt "Invalid change entry" Then a PlanError should be raised with message "Provider stream returned a non-change entry" Scenario: Mock provider resolution keeps nameless provider metadata Given I have a lightweight plan service for actor testing And mock provider mode is forced And the plan service uses a nameless AI provider And the plan service actor lookup returns actor "anthropic/claude-mock" with provider "anthropic" and model "claude-mock" When I resolve provider for actor "anthropic/claude-mock" Then the nameless provider resolution should return provider "anthropic" and model "claude-mock" Scenario: Actor resolution triggers lazy registry creation Given I have a lightweight plan service for actor testing And I stub the provider registry factory for lazy initialization And the plan service actor lookup returns actor "anthropic/claude-dev" with provider "anthropic" and model "claude-dev" When I resolve provider for actor "anthropic/claude-dev" Then the lazy registry should memoize provider "anthropic" and model "claude-dev" Scenario: LangSmith config omits missing metadata Given I have a temporary test directory for plan service And LangSmith integration is enabled for plan service When I prepare a LangSmith config without plan metadata for project "ephemeral-project" Then the LangSmith builder should receive only base metadata for project "ephemeral-project" And the prepared LangSmith config should include a generated thread id Scenario: Build fails when plan ID disappears mid-transaction Given I have a temporary test directory for plan service And I configure a stub plan service whose current plan loses its ID after the transaction When I try to build the plan with the stubbed service Then a PlanError should be raised with message "Plan does not have a valid ID" Scenario: Clearing memory without forgetting history keeps cached messages Given I have a lightweight plan service for actor testing And I stored a chat message in session "ephemeral-branch" When I clear the session "ephemeral-branch" memory without forgetting history Then the session "ephemeral-branch" memory should retain its stored messages Scenario: Actor resolution fails when actor service is missing Given I have a lightweight plan service for actor testing When I try to resolve actor "ghost/actor" Then a PlanError should be raised with message "Actor support is not configured" Scenario: Actor lookup validation errors surface as plan errors Given I have a lightweight plan service for actor testing And the plan service actor lookup raises ValidationError "invalid actor selection" When I try to resolve actor "invalid/actor" Then a PlanError should be raised with message "invalid actor selection" And the PlanError should include actor detail "invalid/actor" Scenario: Actor fallback fails when mock provisioning returns nothing Given I have a lightweight plan service for actor testing And the plan service actor lookup returns no actor and mock provisioning fails When I try to resolve actor "openai/gpt-4o" Then a PlanError should be raised with message "No actor configured" Scenario: Actor resolution returns explicit actors Given I have a lightweight plan service for actor testing And the plan service actor lookup returns actor "openai/gpt-4o" with provider "openai" and model "gpt-4o" When I try to resolve actor "openai/gpt-4o" Then the actor resolution should return actor "openai/gpt-4o" from source "explicit" Scenario: Mock actor provider resolution requires configured AI provider Given I have a lightweight plan service for actor testing And mock provider mode is forced And the plan service actor lookup returns actor "mock/provider" with provider "mock-provider" and model "mock-model" When I resolve provider for actor "mock/provider" Then a PlanError should be raised with message "No AI provider configured" Scenario: Mock actor provider resolution uses injected provider defaults Given I have a lightweight plan service for actor testing And mock provider mode is forced And the plan service AI provider is "injected-provider" with model "injected-model" And the plan service actor lookup returns actor "mock/provider" with provider "mock-provider" and model "mock-model" When I resolve provider for actor "mock/provider" Then the provider resolution should return provider "mock-provider" and model "mock-model" Scenario: Mock actor provider appears after initial check Given I have a Unit of Work instance for plan testing And the plan service uses a delayed mock provider And the plan service actor lookup returns actor "mock/provider" with provider "mock-provider" and model "mock-model" When I resolve provider for actor "mock/provider" Then the provider resolution should return provider "mock-provider" and model "mock-model" Scenario: Actor provider registry factory failure surfaces PlanError Given I have a lightweight plan service for actor testing And the plan service actor lookup returns actor "broken/provider" with provider "broken-provider" and model "broken-model" And the provider registry factory raises ValueError "actor registry missing" for actor providers When I resolve provider for actor "broken/provider" Then a PlanError should be raised with message "actor registry missing" Scenario: Actor provider registry errors surface as PlanError Given I have a lightweight plan service for actor testing And the plan service actor lookup returns actor "anthropic/haiku" with provider "anthropic" and model "haiku" And the provider registry raises ValueError "actor registry unavailable" for actor providers When I resolve provider for actor "anthropic/haiku" Then a PlanError should be raised with message "actor registry unavailable" Scenario: Actor provider registry resolves provider and model Given I have a lightweight plan service for actor testing And the plan service actor lookup returns actor "openai/gpt-4o" with provider "openai" and model "gpt-4o" And the provider registry returns provider "openai" with model "gpt-4o" When I resolve provider for actor "openai/gpt-4o" Then the provider resolution should return provider "openai" and model "gpt-4o" Scenario: Actor provider resolution uses lazy registry fallback Given I have a lightweight plan service for actor testing And the plan service actor lookup returns actor "openai/gpt-4o" with provider "openai" and model "gpt-4o" And I stub the provider registry factory for lazy initialization When I resolve provider for actor "openai/gpt-4o" Then the lazy registry should record actor provider "openai" and model "gpt-4o" Scenario: Streaming sanitization reports unrecoverable Python syntax Given I have a plan service with an unrecoverable streaming provider When I try to stream plan generation with prompt "Fatal stream" Then a PlanError should be raised containing "Validation failed: Syntax error"