Each task includes: - Scope: what to build - Implementation: code sketches + details - Verification: concrete test criteria - Done criteria: acceptance checklist
73 lines
2.1 KiB
Markdown
73 lines
2.1 KiB
Markdown
# T0.4: Pi & Error Classification
|
|
|
|
## Scope
|
|
Implement `action/skills.go` with `PrepareSkillsActivity` and `classifyPiErr` for skill prep via homelab API.
|
|
|
|
## Implementation
|
|
|
|
### File: `action/skills.go`
|
|
```go
|
|
type SkillRef struct {
|
|
Name string
|
|
URL string
|
|
}
|
|
|
|
type PrepareSkillsInput struct {
|
|
Skills []SkillRef
|
|
StreamTimeout time.Duration
|
|
}
|
|
|
|
func PrepareSkillsActivity(ctx context.Context, in PrepareSkillsInput) error
|
|
// For each skill, run: pi clone-or-fetch $skill.URL
|
|
// Pass --stream-timeout=$StreamTimeout to pi
|
|
// Each skill behind its own lock (not orchestrator.lock)
|
|
// On error, return classified error (see below)
|
|
|
|
func classifyPiErr(err error) error
|
|
// 4xx (400-499): NonRetryableApplicationError "PiClientError"
|
|
// 504: ApplicationError "PiStreamTimeout"
|
|
// 5xx (500-599, except 504): leave retryable
|
|
// Other network errors: leave retryable
|
|
```
|
|
|
|
## Error Buckets
|
|
|
|
### Bucket 1: 4xx (PiClientError)
|
|
- Status code 400-499
|
|
- Non-retryable: bad request, auth error, not found
|
|
- Temporal stops retrying immediately
|
|
- Activity fails
|
|
|
|
### Bucket 2: 5xx except 504 (generic 5xx)
|
|
- Status code 500-503, 505-599
|
|
- Retryable: server error, likely transient
|
|
- Temporal backs off + retries until `ScheduleToCloseTimeout` (5m)
|
|
|
|
### Bucket 3: 504 (PiStreamTimeout)
|
|
- Status code 504
|
|
- Means pi's SSE stream-read timed out
|
|
- Retryable, BUT: Orchestrator doubles `config.Tuning.PiRetry.StreamTimeout` before retry
|
|
- Next attempt uses wider timeout
|
|
|
|
## Verification
|
|
```bash
|
|
cd /Users/rockliang/workplace/Poimen/workflows
|
|
go test -v ./tests -run TestPiErrors
|
|
|
|
# Test file: tests/pi_test.go
|
|
```
|
|
|
|
Test cases:
|
|
- Mock 400 response → NonRetryableApplicationError returned
|
|
- Mock 403 response → NonRetryableApplicationError returned
|
|
- Mock 500 response → retryable error returned
|
|
- Mock 503 response → retryable error returned
|
|
- Mock 504 response → ApplicationError type "PiStreamTimeout" returned
|
|
- Mock network timeout → retryable error returned
|
|
|
|
## Done Criteria
|
|
- `go test ./tests -run TestPiErrors` passes all 6 test cases
|
|
- All error buckets correctly classified
|
|
- No panics on nil pointers
|
|
- Error messages include HTTP status code
|