---
phase: 02-command-test-coverage
plan: 01
type: tdd
wave: 1
depends_on: []
files_modified:
  - cmd/start.go
  - cmd/start_test.go
autonomous: true
requirements:
  - TST-01
must_haves:
  truths:
    - "Running `task test:unit` exercises start.go RunE — all four guard paths are tested"
    - "An invalid slug passed to start RunE returns a non-nil error without any API call"
    - "A simulated API failure in GetChallenge returns a non-nil error from RunE — no panic"
    - "Progress status 'in_progress' or 'completed' causes RunE to return nil without deploying"
  artifacts:
    - path: "cmd/start.go"
      provides: "Function vars apiGetChallenge, apiGetChallengeProgress, apiStartChallenge fronting direct api.* calls"
      contains: "var apiGetChallenge"
    - path: "cmd/start_test.go"
      provides: "Unit tests for start.go RunE guards"
      exports: ["TestStartRunE_InvalidSlug", "TestStartRunE_AlreadyInProgress", "TestStartRunE_AlreadyCompleted", "TestStartRunE_APIFailure"]
  key_links:
    - from: "cmd/start_test.go"
      to: "cmd/start.go"
      via: "package cmd — direct unexported var access"
      pattern: "apiGetChallenge\\s*="
---

<objective>
Add function-variable injection points to start.go and write four unit tests covering its flow guards.

Purpose: TST-01 — start.go RunE has zero test coverage today. The guards (slug validation, progress state machine, API failure) are the only parts testable without a real Kubernetes cluster.
Output: cmd/start.go with three function vars; cmd/start_test.go with four passing tests.
</objective>

<execution_context>
@/Users/paul/.claude/get-shit-done/workflows/execute-plan.md
@/Users/paul/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/02-command-test-coverage/02-CONTEXT.md
@.planning/phases/02-command-test-coverage/02-RESEARCH.md
</context>

<interfaces>
<!-- Key types and contracts the executor needs. Extracted from codebase. -->

From internal/api/types.go:
```go
type ChallengeResponse struct {
    ID               int    `json:"id"`
    Title            string `json:"title"`
    Slug             string `json:"slug"`
    Description      string `json:"description"`
    Difficulty       string `json:"difficulty"`
    Theme            string `json:"theme"`
    InitialSituation string `json:"initial_situation"`
}
type ChallengeStatusResponse struct {
    Status      string  `json:"status"` // "not_started" | "in_progress" | "completed"
    StartedAt   *string `json:"startedAt,omitempty"`
    CompletedAt *string `json:"completedAt,omitempty"`
}
type ChallengeEntity = ChallengeResponse
```

From internal/api/client.go:
```go
func GetChallenge(slug string) (*ChallengeEntity, error)
func GetChallengeProgress(slug string) (*ChallengeStatusResponse, error)
func StartChallenge(slug string) error
```

Existing test pattern from cmd/common_test.go:
```go
package cmd  // same package — accesses unexported symbols

import (
    "testing"
    "github.com/stretchr/testify/assert"
)

func TestValidateChallengeSlug(t *testing.T) {
    tests := []struct{ name string; slug string; wantErr bool }{ ... }
    for _, tc := range tests {
        tc := tc
        t.Run(tc.name, func(t *testing.T) { ... })
    }
}
```
</interfaces>

<tasks>

<task type="auto" tdd="true">
  <name>Task 1: Add function vars to start.go and write start_test.go</name>
  <files>cmd/start.go, cmd/start_test.go</files>
  <behavior>
    - TestStartRunE_InvalidSlug: args=["INVALID_SLUG"] → RunE returns non-nil error containing "invalid challenge slug"
    - TestStartRunE_AlreadyInProgress: apiGetChallenge returns ChallengeEntity{Title:"Test"}, apiGetChallengeProgress returns ChallengeStatusResponse{Status:"in_progress"} → RunE returns nil
    - TestStartRunE_AlreadyCompleted: apiGetChallenge returns ChallengeEntity{Title:"Test"}, apiGetChallengeProgress returns ChallengeStatusResponse{Status:"completed"} → RunE returns nil
    - TestStartRunE_APIFailure: apiGetChallenge returns (nil, fmt.Errorf("network error")) → RunE returns non-nil error; assert.NotPanics confirms no panic
  </behavior>
  <action>
**RED phase — write tests first, then make them pass.**

**Step 1: Write failing tests in cmd/start_test.go**

Create cmd/start_test.go in package cmd. Import "fmt", "testing", "github.com/stretchr/testify/assert", "github.com/stretchr/testify/require", "github.com/kubeasy-dev/kubeasy-cli/internal/api".

Write the four test functions described in the behavior block. Each test that uses function vars must save the original with `orig := apiGetChallenge` and restore with `t.Cleanup(func() { apiGetChallenge = orig })`. Call `startChallengeCmd.RunE(startChallengeCmd, []string{"pod-evicted"})` directly — do NOT use rootCmd.Execute(). Do NOT call t.Parallel() on tests mutating package-level vars.

Run `go test ./cmd/... -run TestStartRunE -v` — tests should FAIL because the vars do not exist yet.

**Step 2: Add function vars to cmd/start.go**

At package level (after imports, before var startChallengeCmd), add:
```go
var (
    apiGetChallenge         = api.GetChallenge
    apiGetChallengeProgress = api.GetChallengeProgress
    apiStartChallenge       = api.StartChallenge
)
```

Replace the three direct api.* call sites in RunE:
- Line 34: `challenge, err = api.GetChallenge(challengeSlug)` → `challenge, err = apiGetChallenge(challengeSlug)`
- Line 48: `progress, err = api.GetChallengeProgress(challengeSlug)` → `progress, err = apiGetChallengeProgress(challengeSlug)`
- Line 106: `return api.StartChallenge(challengeSlug)` → `return apiStartChallenge(challengeSlug)`

**Step 3: Run tests — they should pass GREEN**

Run `go test ./cmd/... -run TestStartRunE -v -race`. All four tests must pass. No data races.

**Constraint:** Tests only cover guards before the Kubernetes call at line 67 (kube.GetDynamicClient). Do NOT attempt to mock kube or deployer. The three testable paths that return before Kubernetes calls are: invalid slug (line 24-26), progress in_progress/completed (line 56-60), and apiGetChallenge error (line 37-40).
  </action>
  <verify>
    <automated>cd /Users/paul/Workspace/kubeasy/kubeasy-cli && go test ./cmd/... -run TestStartRunE -v -race</automated>
  </verify>
  <done>Four TestStartRunE_* tests pass with -race. cmd/start.go compiles with three function vars. `task test:unit` remains green.</done>
</task>

</tasks>

<verification>
Run `task test:unit` — full unit test suite must pass green with no race conditions.
Run `go test ./cmd/... -v -race` — all cmd tests pass including the four new TestStartRunE_* tests.
</verification>

<success_criteria>
- cmd/start_test.go exists with TestStartRunE_InvalidSlug, TestStartRunE_AlreadyInProgress, TestStartRunE_AlreadyCompleted, TestStartRunE_APIFailure
- cmd/start.go has vars apiGetChallenge, apiGetChallengeProgress, apiStartChallenge at package level
- All four tests pass with `go test ./cmd/... -run TestStartRunE -v -race`
- TST-01 requirement satisfied: slug validation, progress state machine, API failure all exercised
</success_criteria>

<output>
After completion, create `.planning/phases/02-command-test-coverage/02-01-SUMMARY.md`
</output>
