Task 1.1 COMPLETE ✅ Core type definitions for routing workflows: - WorkflowSpec: One-time workflow specification - CronWorkflowSpec: Scheduled workflow specification - State: Individual step in workflow (Task/Pass/Fail) - RetryPolicy: Retry configuration with backoff - CatchClause: Error handling - ExecutionContext: Tracks state during execution - ActivityMetadata: Describes activity capabilities - Supporting types: PollParams, Heartbeat, Result All types support JSON marshaling/unmarshaling. 8 unit tests covering complex scenarios (9/9 PASS). Acceptance criteria met: ✅ All types compile without errors ✅ JSON marshaling/unmarshaling works correctly ✅ Unit tests pass (complex workflow examples) ✅ Ready for next phase (Knowledge Base) Effort: 2 hours Files: internal/routing/types.go (159 lines) internal/routing/types_test.go (286 lines)
1159 lines
27 KiB
Markdown
1159 lines
27 KiB
Markdown
# Poimen Routing Workflow - Implementation Tasks
|
|
|
|
**Total Effort**: 60-70 hours (2-3 weeks, 1-2 engineers)
|
|
|
|
---
|
|
|
|
## PHASE 1: FOUNDATION (8-10 hours)
|
|
|
|
### Task 1.1: Create Go Type Definitions
|
|
|
|
**File**: `internal/routing/types.go`
|
|
|
|
**What to create**:
|
|
```go
|
|
// Core types
|
|
type WorkflowSpec struct {
|
|
Name string
|
|
Input map[string]interface{}
|
|
States []State
|
|
}
|
|
|
|
type State struct {
|
|
Name string
|
|
Type StateType
|
|
Resource string
|
|
Parameters map[string]interface{}
|
|
Timeout string
|
|
Retry *RetryPolicy
|
|
Catch []CatchClause
|
|
Result interface{}
|
|
Error, Cause string
|
|
Next string
|
|
End bool
|
|
}
|
|
|
|
type StateType string
|
|
const (
|
|
StateTypeTask StateType = "Task"
|
|
StateTypePass StateType = "Pass"
|
|
StateTypeFail StateType = "Fail"
|
|
)
|
|
|
|
type RetryPolicy struct {
|
|
MaxAttempts int32
|
|
BackoffRate float64
|
|
InitialInterval string
|
|
MaxInterval string
|
|
}
|
|
|
|
type CatchClause struct {
|
|
ErrorEquals []string
|
|
Next string
|
|
}
|
|
|
|
// Cron types
|
|
type CronWorkflowSpec struct {
|
|
Name string
|
|
Type string // "CronWorkflow"
|
|
Schedule string // "0 2 * * *"
|
|
Timezone string
|
|
Input map[string]interface{}
|
|
States []State
|
|
MaxConcurrent int
|
|
Timeout string
|
|
EnableHistory bool
|
|
}
|
|
|
|
type ExecutionContext struct {
|
|
Input map[string]interface{}
|
|
StepResults map[string]interface{}
|
|
}
|
|
|
|
type Result struct {
|
|
FinalOutput interface{}
|
|
Status string
|
|
Error error
|
|
}
|
|
```
|
|
|
|
**Acceptance Criteria**:
|
|
- [ ] All types compile
|
|
- [ ] JSON marshaling/unmarshaling works
|
|
- [ ] Unit tests for type serialization
|
|
|
|
**Effort**: 2 hours
|
|
|
|
---
|
|
|
|
### Task 1.2: Create ActivityKnowledgeBase.json
|
|
|
|
**File**: `internal/routing/activity_knowledge_base.json`
|
|
|
|
**What to create**:
|
|
```json
|
|
{
|
|
"activities": [
|
|
{
|
|
"name": "CloneRepoActivity",
|
|
"description": "Clone a Git repository",
|
|
"category": "source-control",
|
|
"inputs": {
|
|
"repo": {"type": "string", "required": true},
|
|
"branch": {"type": "string", "required": false, "default": "main"}
|
|
},
|
|
"outputs": {
|
|
"path": {"type": "string"},
|
|
"commit": {"type": "string"}
|
|
},
|
|
"constraints": {
|
|
"defaultTimeout": "5m",
|
|
"isFlaky": false,
|
|
"recommendedRetries": 2,
|
|
"retryBackoff": 1.5
|
|
}
|
|
},
|
|
{
|
|
"name": "AnalyzeCodeActivity",
|
|
"description": "Analyze code for quality",
|
|
"category": "analysis",
|
|
"inputs": {
|
|
"path": {"type": "string", "required": true}
|
|
},
|
|
"outputs": {
|
|
"quality": {"type": "number"},
|
|
"issues": {"type": "array"}
|
|
},
|
|
"constraints": {
|
|
"defaultTimeout": "10m",
|
|
"isFlaky": true,
|
|
"recommendedRetries": 3,
|
|
"retryBackoff": 2.0
|
|
}
|
|
},
|
|
// Add 5-7 more activities (SecurityScanActivity, PerformanceAnalysisActivity, etc)
|
|
]
|
|
}
|
|
```
|
|
|
|
**Acceptance Criteria**:
|
|
- [ ] Valid JSON format
|
|
- [ ] At least 7 activities defined
|
|
- [ ] Each has description, inputs, outputs, constraints
|
|
- [ ] Includes both flaky and non-flaky activities
|
|
- [ ] JSON loads without error
|
|
|
|
**Effort**: 3 hours
|
|
|
|
---
|
|
|
|
### Task 1.3: Create ActivityKnowledgeBase Loader
|
|
|
|
**File**: `internal/routing/activity_knowledge_base.go`
|
|
|
|
**What to create**:
|
|
```go
|
|
type ActivityKnowledgeBase struct {
|
|
Activities map[string]*ActivityMetadata
|
|
}
|
|
|
|
type ActivityMetadata struct {
|
|
Name string
|
|
Description string
|
|
Category string
|
|
Inputs map[string]InputField
|
|
Outputs map[string]OutputField
|
|
Constraints Constraints
|
|
}
|
|
|
|
type Constraints struct {
|
|
DefaultTimeout string
|
|
IsFlaky bool
|
|
RecommendedRetries int
|
|
RetryBackoff float64
|
|
}
|
|
|
|
// Load from JSON file
|
|
func LoadActivityKnowledgeBase(path string) (*ActivityKnowledgeBase, error) {
|
|
// Load JSON from file
|
|
// Parse into ActivityKnowledgeBase
|
|
// Return
|
|
}
|
|
|
|
// Get activity by name
|
|
func (kb *ActivityKnowledgeBase) GetActivity(name string) *ActivityMetadata
|
|
|
|
// Get all activities in category
|
|
func (kb *ActivityKnowledgeBase) GetByCategory(category string) []*ActivityMetadata
|
|
```
|
|
|
|
**Acceptance Criteria**:
|
|
- [ ] Loads JSON successfully
|
|
- [ ] GetActivity() works
|
|
- [ ] GetByCategory() works
|
|
- [ ] Unit tests pass
|
|
|
|
**Effort**: 2 hours
|
|
|
|
---
|
|
|
|
### Task 1.4: Create WorkflowSpec Validator
|
|
|
|
**File**: `internal/routing/validator.go`
|
|
|
|
**What to validate**:
|
|
```go
|
|
func ValidateWorkflowSpec(spec *WorkflowSpec) error {
|
|
// 1. All states have unique names
|
|
// 2. All state.next references exist
|
|
// 3. All catch.next references exist
|
|
// 4. All Task states have resource defined
|
|
// 5. No circular loops (A→B→C→A)
|
|
// 6. At least one path leads to end
|
|
// 7. No dead ends
|
|
// 8. Timeout format valid (e.g., "5m")
|
|
// 9. Retry settings valid
|
|
// 10. JSONPath expressions syntactically valid
|
|
}
|
|
|
|
func ValidateCronExpression(schedule string) error {
|
|
// Use cronexpr library
|
|
// Parse and validate
|
|
}
|
|
```
|
|
|
|
**Acceptance Criteria**:
|
|
- [ ] Catches all 10 validation errors
|
|
- [ ] Unit tests for each error type
|
|
- [ ] Cron expression validation works
|
|
- [ ] Clear error messages
|
|
|
|
**Effort**: 3 hours
|
|
|
|
---
|
|
|
|
## PHASE 2: LLM-ROUTER ACTIVITY (12-15 hours)
|
|
|
|
### Task 2.1: Create JSONPath Resolver
|
|
|
|
**File**: `internal/routing/jsonpath_evaluator.go`
|
|
|
|
**What to create**:
|
|
```go
|
|
func ResolveJSONPath(expr interface{}, ec *ExecutionContext) interface{} {
|
|
// Support:
|
|
// ${input.repo} → from ec.Input
|
|
// ${Clone.output.path} → from ec.StepResults["Clone"]["output"]["path"]
|
|
// ${input.branch:main} → default value "main"
|
|
}
|
|
|
|
func ResolveParameters(params map[string]interface{}, ec *ExecutionContext) map[string]interface{} {
|
|
// Resolve all JSONPath expressions in params
|
|
}
|
|
|
|
func getNestedValue(obj interface{}, path []string) interface{} {
|
|
// Handle nested object access
|
|
}
|
|
```
|
|
|
|
**Test cases**:
|
|
```go
|
|
// Test: ${input.repo}
|
|
// Test: ${Clone.output.path}
|
|
// Test: ${Analyze.output.issues[0]}
|
|
// Test: ${input.branch:main} with default
|
|
// Test: Literal values (no JSONPath)
|
|
// Test: Nested objects
|
|
```
|
|
|
|
**Acceptance Criteria**:
|
|
- [ ] All JSONPath expressions resolve correctly
|
|
- [ ] Default values work
|
|
- [ ] Array access works
|
|
- [ ] Nested objects work
|
|
- [ ] 15+ unit tests pass
|
|
|
|
**Effort**: 3 hours
|
|
|
|
---
|
|
|
|
### Task 2.2: Create llm-router Activity Skeleton
|
|
|
|
**File**: `cmd/worker/activities/llm_router.go`
|
|
|
|
**What to create**:
|
|
```go
|
|
type LLMRouterInput struct {
|
|
Message string
|
|
Repo string
|
|
Branch string
|
|
}
|
|
|
|
func LLMRouterActivity(ctx context.Context, input LLMRouterInput) (routing.WorkflowSpec, error) {
|
|
// 1. Load activity knowledge base
|
|
kb, err := routing.LoadActivityKnowledgeBase()
|
|
|
|
// 2. Create LLM prompt
|
|
// (use memory service to call LLM)
|
|
|
|
// 3. Parse LLM response to understand intent
|
|
intent := parseLLMResponse(llmOutput)
|
|
|
|
// 4. Build workflow spec
|
|
spec := buildWorkflowSpec(intent, input, kb)
|
|
|
|
// 5. Validate spec
|
|
if err := routing.ValidateWorkflowSpec(&spec); err != nil {
|
|
return routing.WorkflowSpec{}, err
|
|
}
|
|
|
|
return spec, nil
|
|
}
|
|
```
|
|
|
|
**Acceptance Criteria**:
|
|
- [ ] Activity compiles
|
|
- [ ] Loads knowledge base successfully
|
|
- [ ] Can be registered in worker
|
|
|
|
**Effort**: 2 hours
|
|
|
|
---
|
|
|
|
### Task 2.3: Implement LLM Intent Analysis
|
|
|
|
**File**: `cmd/worker/activities/llm_intent.go`
|
|
|
|
**What to analyze**:
|
|
```go
|
|
type Intent struct {
|
|
IsScheduled bool
|
|
Schedule string // Cron expression if scheduled
|
|
Timezone string
|
|
SelectedActivities []string
|
|
ActivityDependencies map[string][]string
|
|
NeedsFinalJudgment bool
|
|
NeedsNotification bool
|
|
}
|
|
|
|
func analyzeLLMIntent(ctx context.Context, kb *ActivityKnowledgeBase, message string) (Intent, error) {
|
|
// Use LLM to understand:
|
|
// 1. Is this a scheduled job? Extract cron expression
|
|
// 2. Which activities are needed?
|
|
// 3. What order?
|
|
// 4. Does it need error handling?
|
|
// 5. What parameters to pass?
|
|
}
|
|
|
|
func extractCronFromMessage(message string) string {
|
|
// Use LLM to convert:
|
|
// "every day at 2 AM" → "0 2 * * *"
|
|
// "every 6 hours" → "0 */6 * * *"
|
|
// etc
|
|
}
|
|
```
|
|
|
|
**Acceptance Criteria**:
|
|
- [ ] Detects scheduled workflows (contains "daily", "every", etc)
|
|
- [ ] Extracts cron expressions correctly
|
|
- [ ] Identifies required activities
|
|
- [ ] Orders activities by dependencies
|
|
- [ ] Integration tests with real LLM calls
|
|
|
|
**Effort**: 5 hours
|
|
|
|
---
|
|
|
|
### Task 2.4: Implement Workflow Spec Builder
|
|
|
|
**File**: `cmd/worker/activities/spec_builder.go`
|
|
|
|
**What to build**:
|
|
```go
|
|
func buildWorkflowSpec(intent Intent, input LLMRouterInput, kb *ActivityKnowledgeBase) routing.WorkflowSpec {
|
|
// 1. Create initial states (always Clone first)
|
|
// 2. Add selected activities in order
|
|
// 3. For each activity:
|
|
// - Get timeout from knowledge base
|
|
// - Get retry settings from knowledge base
|
|
// - If flaky: add error handling
|
|
// - Chain parameters (JSONPath)
|
|
// 4. Add final state (notification or pass)
|
|
// 5. Add error handlers
|
|
// 6. Return complete spec
|
|
}
|
|
|
|
func createStateForActivity(activity *ActivityMetadata, previousState string, nextStateName string) routing.State {
|
|
// Create a Task state with intelligent settings
|
|
}
|
|
|
|
func chainParameters(activity *ActivityMetadata, previousStates map[string]interface{}) map[string]interface{} {
|
|
// Use LLM to map outputs from previous steps to inputs of this activity
|
|
// E.g.: Clone.output.path → AnalyzeCodeActivity.path
|
|
}
|
|
```
|
|
|
|
**Acceptance Criteria**:
|
|
- [ ] Generates valid WorkflowSpec
|
|
- [ ] States ordered correctly
|
|
- [ ] Timeout from knowledge base
|
|
- [ ] Retry policy from knowledge base
|
|
- [ ] Error handlers for flaky activities
|
|
- [ ] JSONPath chaining works
|
|
- [ ] 10+ integration tests
|
|
|
|
**Effort**: 4 hours
|
|
|
|
---
|
|
|
|
### Task 2.5: Implement Cron Workflow Generation
|
|
|
|
**File**: `cmd/worker/activities/cron_builder.go`
|
|
|
|
**What to build**:
|
|
```go
|
|
func buildCronWorkflowSpec(intent Intent, input LLMRouterInput, kb *ActivityKnowledgeBase) routing.CronWorkflowSpec {
|
|
// 1. Extract schedule and timezone
|
|
// 2. Build states (same as regular workflow)
|
|
// 3. Create CronWorkflowSpec
|
|
// 4. Return
|
|
}
|
|
|
|
func validateCronSchedule(schedule string) error {
|
|
// Use cronexpr library
|
|
// Validate cron expression
|
|
}
|
|
```
|
|
|
|
**Acceptance Criteria**:
|
|
- [ ] Generates valid CronWorkflowSpec
|
|
- [ ] Schedule is valid cron expression
|
|
- [ ] Timezone is valid
|
|
- [ ] Same states as one-time workflow
|
|
- [ ] 5+ test cases
|
|
|
|
**Effort**: 2 hours
|
|
|
|
---
|
|
|
|
## PHASE 3: ROUTING WORKFLOW EXECUTOR (15-18 hours)
|
|
|
|
### Task 3.1: Create State Executor Dispatcher
|
|
|
|
**File**: `statemachine/routing_workflow.go` (Part 1)
|
|
|
|
**What to create**:
|
|
```go
|
|
func ExecuteState(ctx workflow.Context, state *routing.State, ec *routing.ExecutionContext) (interface{}, error) {
|
|
switch state.Type {
|
|
case routing.StateTypeTask:
|
|
return ExecuteTaskState(ctx, state, ec)
|
|
case routing.StateTypePass:
|
|
return ExecutePassState(ctx, state, ec)
|
|
case routing.StateTypeFail:
|
|
return ExecuteFailState(ctx, state, ec)
|
|
default:
|
|
return nil, fmt.Errorf("unknown state type: %s", state.Type)
|
|
}
|
|
}
|
|
```
|
|
|
|
**Acceptance Criteria**:
|
|
- [ ] Compiles
|
|
- [ ] Routes to correct executor
|
|
- [ ] Unit tests for each type
|
|
|
|
**Effort**: 1 hour
|
|
|
|
---
|
|
|
|
### Task 3.2: Implement Task Executor
|
|
|
|
**File**: `internal/routing/task_executor.go`
|
|
|
|
**What to create**:
|
|
```go
|
|
func ExecuteTaskState(ctx workflow.Context, state *routing.State, ec *routing.ExecutionContext) (interface{}, error) {
|
|
// 1. Resolve JSONPath in parameters
|
|
resolvedParams := routing.ResolveJSONPath(state.Parameters, ec)
|
|
|
|
// 2. Parse timeout
|
|
timeout := routing.ParseDuration(state.Timeout)
|
|
|
|
// 3. Build activity options
|
|
options := workflow.ActivityOptions{
|
|
StartToCloseTimeout: timeout,
|
|
}
|
|
|
|
// 4. Add retry policy if specified
|
|
if state.Retry != nil {
|
|
options.RetryPolicy = &temporal.RetryPolicy{
|
|
InitialInterval: routing.ParseDuration(state.Retry.InitialInterval),
|
|
BackoffCoefficient: state.Retry.BackoffRate,
|
|
MaximumInterval: routing.ParseDuration(state.Retry.MaxInterval),
|
|
MaximumAttempts: state.Retry.MaxAttempts,
|
|
}
|
|
}
|
|
|
|
// 5. Execute activity
|
|
actCtx := workflow.WithActivityOptions(ctx, options)
|
|
var result interface{}
|
|
err := workflow.ExecuteActivity(
|
|
actCtx,
|
|
state.Resource,
|
|
resolvedParams,
|
|
).Get(actCtx, &result)
|
|
|
|
return result, err
|
|
}
|
|
```
|
|
|
|
**Acceptance Criteria**:
|
|
- [ ] Resolves JSONPath correctly
|
|
- [ ] Parses timeout/retry
|
|
- [ ] Executes activity
|
|
- [ ] Returns result or error
|
|
- [ ] Unit tests
|
|
|
|
**Effort**: 2 hours
|
|
|
|
---
|
|
|
|
### Task 3.3: Implement Pass & Fail Executors
|
|
|
|
**File**: `internal/routing/pass_fail_executor.go`
|
|
|
|
**What to create**:
|
|
```go
|
|
func ExecutePassState(ctx workflow.Context, state *routing.State, ec *routing.ExecutionContext) (interface{}, error) {
|
|
return state.Result, nil
|
|
}
|
|
|
|
func ExecuteFailState(ctx workflow.Context, state *routing.State, ec *routing.ExecutionContext) (interface{}, error) {
|
|
return nil, fmt.Errorf("%s: %s", state.Error, state.Cause)
|
|
}
|
|
```
|
|
|
|
**Acceptance Criteria**:
|
|
- [ ] Pass returns static result
|
|
- [ ] Fail returns error
|
|
- [ ] Unit tests
|
|
|
|
**Effort**: 1 hour
|
|
|
|
---
|
|
|
|
### Task 3.4: Implement Main RoutingWorkflow
|
|
|
|
**File**: `statemachine/routing_workflow.go` (Part 2)
|
|
|
|
**What to create**:
|
|
```go
|
|
func RoutingWorkflow(ctx workflow.Context, spec routing.WorkflowSpec) (routing.Result, error) {
|
|
logger := workflow.GetLogger(ctx)
|
|
|
|
ec := &routing.ExecutionContext{
|
|
Input: spec.Input,
|
|
StepResults: make(map[string]interface{}),
|
|
}
|
|
|
|
currentStateName := routing.FindFirstState(spec.States)
|
|
|
|
for {
|
|
logger.Info("Executing state", "state", currentStateName)
|
|
|
|
state := routing.FindStateByName(spec.States, currentStateName)
|
|
if state == nil {
|
|
return routing.Result{}, fmt.Errorf("state not found: %s", currentStateName)
|
|
}
|
|
|
|
result, err := routing.ExecuteState(ctx, state, ec)
|
|
|
|
if err != nil {
|
|
// Check catch blocks
|
|
handled := false
|
|
for _, catchClause := range state.Catch {
|
|
if routing.MatchesError(err, catchClause.ErrorEquals) {
|
|
logger.Info("Error caught", "handler", catchClause.Next)
|
|
currentStateName = catchClause.Next
|
|
handled = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !handled {
|
|
return routing.Result{
|
|
FinalOutput: ec.StepResults,
|
|
Status: "FAILED",
|
|
Error: err,
|
|
}, nil
|
|
}
|
|
} else {
|
|
ec.StepResults[state.Name] = result
|
|
|
|
if state.End {
|
|
logger.Info("Workflow completed")
|
|
return routing.Result{
|
|
FinalOutput: result,
|
|
Status: "COMPLETED",
|
|
Error: nil,
|
|
}, nil
|
|
}
|
|
|
|
if state.Next == "" {
|
|
return routing.Result{}, fmt.Errorf("state %s has no next and end != true", currentStateName)
|
|
}
|
|
|
|
currentStateName = state.Next
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**Acceptance Criteria**:
|
|
- [ ] Compiles
|
|
- [ ] State machine loop works
|
|
- [ ] Error handling with catch blocks
|
|
- [ ] Transitions correct
|
|
- [ ] 20+ unit tests
|
|
|
|
**Effort**: 4 hours
|
|
|
|
---
|
|
|
|
### Task 3.5: Register RoutingWorkflow in Worker
|
|
|
|
**File**: `cmd/worker/main.go`
|
|
|
|
**What to do**:
|
|
```go
|
|
func main() {
|
|
// Existing worker setup
|
|
|
|
// Register RoutingWorkflow
|
|
w.RegisterWorkflow(statemachine.RoutingWorkflow)
|
|
|
|
// Register all activities (CloneRepoActivity, AnalyzeCodeActivity, etc)
|
|
w.RegisterActivity(CloneRepoActivity)
|
|
w.RegisterActivity(AnalyzeCodeActivity)
|
|
w.RegisterActivity(SecurityScanActivity)
|
|
// ... more activities
|
|
|
|
// Register llm-router activity
|
|
w.RegisterActivity(activities.LLMRouterActivity)
|
|
|
|
// Run worker
|
|
err := w.Run()
|
|
}
|
|
```
|
|
|
|
**Acceptance Criteria**:
|
|
- [ ] Worker starts without error
|
|
- [ ] All workflows/activities registered
|
|
- [ ] Can connect to Temporal
|
|
- [ ] Health check passes
|
|
|
|
**Effort**: 1 hour
|
|
|
|
---
|
|
|
|
### Task 3.6: Implement Helper Functions
|
|
|
|
**File**: `internal/routing/helpers.go`
|
|
|
|
**What to create**:
|
|
```go
|
|
func FindFirstState(states []State) string {
|
|
// Find state with no incoming edges
|
|
}
|
|
|
|
func FindStateByName(states []State, name string) *State {
|
|
// Find state by name
|
|
}
|
|
|
|
func ParseDuration(d string) time.Duration {
|
|
// Parse "5m" → 5 minutes
|
|
// Parse "1h" → 1 hour
|
|
}
|
|
|
|
func MatchesError(err error, errorTypes []string) bool {
|
|
// Check if error matches any of the error types
|
|
}
|
|
```
|
|
|
|
**Acceptance Criteria**:
|
|
- [ ] All helpers work correctly
|
|
- [ ] Unit tests
|
|
|
|
**Effort**: 2 hours
|
|
|
|
---
|
|
|
|
## PHASE 4: API SERVER & CLI (12-15 hours)
|
|
|
|
### Task 4.1: Create API Handlers
|
|
|
|
**File**: `cmd/api-server/handlers.go`
|
|
|
|
**What to create**:
|
|
```go
|
|
// POST /api/v1/workflows (submit one-time workflow)
|
|
func SubmitWorkflowHandler(w http.ResponseWriter, r *http.Request)
|
|
|
|
// GET /api/v1/workflows/{id}/status (check status)
|
|
func GetWorkflowStatusHandler(w http.ResponseWriter, r *http.Request)
|
|
|
|
// POST /api/v1/cron/workflows (submit cron workflow)
|
|
func SubmitCronWorkflowHandler(w http.ResponseWriter, r *http.Request)
|
|
|
|
// GET /api/v1/cron/workflows/{id}/status (check cron status)
|
|
func GetCronStatusHandler(w http.ResponseWriter, r *http.Request)
|
|
|
|
// DELETE /api/v1/cron/workflows/{id} (cancel cron)
|
|
func CancelCronWorkflowHandler(w http.ResponseWriter, r *http.Request)
|
|
```
|
|
|
|
**Acceptance Criteria**:
|
|
- [ ] All endpoints compile
|
|
- [ ] Input validation
|
|
- [ ] Error handling
|
|
- [ ] Response formatting
|
|
- [ ] 10+ integration tests
|
|
|
|
**Effort**: 4 hours
|
|
|
|
---
|
|
|
|
### Task 4.2: Create CLI Commands
|
|
|
|
**File**: `cmd/cli/main.go` and `cmd/cli/commands/`
|
|
|
|
**What to create**:
|
|
```bash
|
|
# Submit one-time workflow
|
|
poimen-cli submit workflow.json --wait
|
|
|
|
# Check status
|
|
poimen-cli status wf-abc123 --wait
|
|
|
|
# Submit cron workflow
|
|
poimen-cli cron submit schedule.json
|
|
|
|
# List cron workflows
|
|
poimen-cli cron list
|
|
|
|
# Cancel cron
|
|
poimen-cli cron cancel daily-security-scan
|
|
|
|
# Execute template (sync)
|
|
poimen-cli execute template code-review-v1 --input input.json
|
|
```
|
|
|
|
**Files needed**:
|
|
```
|
|
cmd/cli/main.go
|
|
cmd/cli/commands/submit.go
|
|
cmd/cli/commands/status.go
|
|
cmd/cli/commands/cron.go
|
|
cmd/cli/commands/template.go
|
|
```
|
|
|
|
**Acceptance Criteria**:
|
|
- [ ] All commands compile
|
|
- [ ] Help text works
|
|
- [ ] Argument parsing
|
|
- [ ] JSON output
|
|
- [ ] 10+ e2e tests
|
|
|
|
**Effort**: 5 hours
|
|
|
|
---
|
|
|
|
### Task 4.3: API Server Bootstrap
|
|
|
|
**File**: `cmd/api-server/main.go`
|
|
|
|
**What to create**:
|
|
```go
|
|
func main() {
|
|
// Load config
|
|
// Create Temporal client
|
|
// Create HTTP server
|
|
// Register handlers
|
|
// Start server
|
|
}
|
|
```
|
|
|
|
**Acceptance Criteria**:
|
|
- [ ] Server starts
|
|
- [ ] Listens on correct port
|
|
- [ ] Can connect to Temporal
|
|
- [ ] Health check endpoint works
|
|
|
|
**Effort**: 2 hours
|
|
|
|
---
|
|
|
|
### Task 4.4: Input Validation
|
|
|
|
**File**: `cmd/api-server/validation.go`
|
|
|
|
**What to validate**:
|
|
```go
|
|
func ValidateWorkflowInput(req WorkflowRequest) error {
|
|
// Check: Is JSON valid?
|
|
// Check: Does it conform to WorkflowSpec?
|
|
// Check: Are all activities registered?
|
|
// Check: Is it safe to execute?
|
|
}
|
|
```
|
|
|
|
**Acceptance Criteria**:
|
|
- [ ] Rejects invalid JSON
|
|
- [ ] Rejects missing required fields
|
|
- [ ] Rejects unknown activities
|
|
- [ ] Clear error messages
|
|
|
|
**Effort**: 2 hours
|
|
|
|
---
|
|
|
|
## PHASE 5: TESTING & INTEGRATION (8-12 hours)
|
|
|
|
### Task 5.1: Unit Tests for Types & Validators
|
|
|
|
**Files**:
|
|
- `internal/routing/types_test.go`
|
|
- `internal/routing/validator_test.go`
|
|
- `internal/routing/jsonpath_evaluator_test.go`
|
|
|
|
**What to test**:
|
|
```
|
|
✅ Type marshaling/unmarshaling
|
|
✅ Validator catches all errors
|
|
✅ JSONPath resolution (15+ cases)
|
|
✅ Cron expression validation
|
|
✅ Activity knowledge base loading
|
|
```
|
|
|
|
**Acceptance Criteria**:
|
|
- [ ] >90% code coverage
|
|
- [ ] All edge cases covered
|
|
- [ ] CI passes
|
|
|
|
**Effort**: 3 hours
|
|
|
|
---
|
|
|
|
### Task 5.2: Integration Tests for Workflows
|
|
|
|
**Files**:
|
|
- `statemachine/routing_workflow_test.go`
|
|
- `cmd/worker/activities/llm_router_test.go`
|
|
|
|
**What to test**:
|
|
```
|
|
✅ Simple sequential workflow (Clone → Analyze → Judge)
|
|
✅ Workflow with retry (timeout on attempt 1, success on attempt 2)
|
|
✅ Workflow with error handling (error caught, jump to handler)
|
|
✅ Workflow with pass state
|
|
✅ LLM-router generates correct spec
|
|
✅ LLM-router detects cron jobs
|
|
```
|
|
|
|
**Acceptance Criteria**:
|
|
- [ ] All scenarios pass
|
|
- [ ] Tests run in <30 seconds
|
|
- [ ] No flaky tests
|
|
|
|
**Effort**: 4 hours
|
|
|
|
---
|
|
|
|
### Task 5.3: End-to-End Tests
|
|
|
|
**Files**:
|
|
- `tests/e2e/workflow_test.go`
|
|
- `tests/e2e/api_test.go`
|
|
- `tests/e2e/cli_test.go`
|
|
|
|
**What to test**:
|
|
```
|
|
✅ User → API → llm-router → RoutingWorkflow → Result
|
|
✅ User → CLI → llm-router → RoutingWorkflow → Result
|
|
✅ Cron workflow submission and scheduling
|
|
✅ Status polling
|
|
✅ Error scenarios (network, timeout, activity failure)
|
|
```
|
|
|
|
**Acceptance Criteria**:
|
|
- [ ] All flows work end-to-end
|
|
- [ ] Can interact with real Temporal
|
|
- [ ] Tests run in <2 minutes
|
|
|
|
**Effort**: 4 hours
|
|
|
|
---
|
|
|
|
### Task 5.4: Load & Performance Tests
|
|
|
|
**Files**:
|
|
- `tests/load/workflow_load_test.go`
|
|
|
|
**What to test**:
|
|
```
|
|
✅ Submit 100 workflows concurrently
|
|
✅ Poll status for 1000 workflows
|
|
✅ Execute 10 sequential workflows
|
|
✅ Measure latency: submit → first activity
|
|
✅ Measure throughput: workflows/second
|
|
```
|
|
|
|
**Acceptance Criteria**:
|
|
- [ ] Submit latency <200ms
|
|
- [ ] Poll latency <100ms
|
|
- [ ] Throughput >10 workflows/sec
|
|
- [ ] No memory leaks
|
|
|
|
**Effort**: 2 hours
|
|
|
|
---
|
|
|
|
## PHASE 6: DOCUMENTATION & DEPLOYMENT (5-8 hours)
|
|
|
|
### Task 6.1: API Documentation
|
|
|
|
**File**: `docs/API.md`
|
|
|
|
**What to document**:
|
|
```
|
|
- All endpoints
|
|
- Request/response formats
|
|
- Error codes
|
|
- Examples (curl, Python, Go)
|
|
- Authentication
|
|
- Rate limits
|
|
```
|
|
|
|
**Acceptance Criteria**:
|
|
- [ ] Complete
|
|
- [ ] All examples work
|
|
- [ ] Clear and concise
|
|
|
|
**Effort**: 2 hours
|
|
|
|
---
|
|
|
|
### Task 6.2: CLI Documentation
|
|
|
|
**File**: `docs/CLI.md`
|
|
|
|
**What to document**:
|
|
```
|
|
- All commands
|
|
- Usage examples
|
|
- Flags and options
|
|
- Output formats
|
|
- Troubleshooting
|
|
```
|
|
|
|
**Acceptance Criteria**:
|
|
- [ ] Complete
|
|
- [ ] All commands documented
|
|
- [ ] Examples work
|
|
|
|
**Effort**: 1 hour
|
|
|
|
---
|
|
|
|
### Task 6.3: Deployment Guide
|
|
|
|
**File**: `docs/DEPLOYMENT.md`
|
|
|
|
**What to document**:
|
|
```
|
|
- Build instructions
|
|
- Docker image
|
|
- K8s deployment (api-server, worker)
|
|
- Configuration
|
|
- Troubleshooting
|
|
- Monitoring
|
|
```
|
|
|
|
**Acceptance Criteria**:
|
|
- [ ] Complete
|
|
- [ ] Can deploy from instructions
|
|
- [ ] Includes health checks
|
|
|
|
**Effort**: 2 hours
|
|
|
|
---
|
|
|
|
### Task 6.4: User Guide & Examples
|
|
|
|
**File**: `docs/USER_GUIDE.md`
|
|
|
|
**What to include**:
|
|
```
|
|
- Getting started
|
|
- 5+ workflow examples (code review, security scan, health check, etc)
|
|
- How to create custom activities
|
|
- How to use cron jobs
|
|
- FAQ
|
|
```
|
|
|
|
**Acceptance Criteria**:
|
|
- [ ] Complete
|
|
- [ ] All examples runnable
|
|
- [ ] Clear explanations
|
|
|
|
**Effort**: 2 hours
|
|
|
|
---
|
|
|
|
## TIMELINE & PHASES
|
|
|
|
```
|
|
Phase 1: Foundation (8-10 hours)
|
|
├─ Types, Knowledge Base, Validator
|
|
└─ Week 1 (Mon-Tue)
|
|
|
|
Phase 2: LLM-Router (12-15 hours)
|
|
├─ Intent Analysis, Spec Builder, Cron Builder
|
|
└─ Week 1 (Wed-Fri) + Week 2 (Mon)
|
|
|
|
Phase 3: RoutingWorkflow (15-18 hours)
|
|
├─ Executors, State Machine, Registration
|
|
└─ Week 2 (Tue-Thu)
|
|
|
|
Phase 4: API/CLI (12-15 hours)
|
|
├─ Handlers, Commands, Validation
|
|
└─ Week 2 (Fri) + Week 3 (Mon-Tue)
|
|
|
|
Phase 5: Testing (8-12 hours)
|
|
├─ Unit, Integration, E2E, Load tests
|
|
└─ Week 3 (Wed-Fri)
|
|
|
|
Phase 6: Documentation (5-8 hours)
|
|
├─ API, CLI, Deployment, User Guide
|
|
└─ Week 3 (Fri) + Week 4 (Mon)
|
|
|
|
TOTAL: 60-70 hours (3 weeks, 1-2 engineers)
|
|
```
|
|
|
|
---
|
|
|
|
## DEPENDENCIES
|
|
|
|
```
|
|
Task 1.1 Types → Required by all others
|
|
Task 1.2 Knowledge Base → Required by Task 2.x
|
|
Task 1.3 KB Loader → Required by Task 2.x
|
|
Task 1.4 Validator → Required by Task 2.x & 3.x
|
|
↓
|
|
Task 2.x LLM-Router → Required by Task 3.x
|
|
↓
|
|
Task 3.x RoutingWorkflow → Required by Task 4.x & 5.x
|
|
↓
|
|
Task 4.x API/CLI → Can run in parallel with Task 5.x
|
|
↓
|
|
Task 5.x Testing → Gate to Task 6.x
|
|
↓
|
|
Task 6.x Documentation → Final deliverable
|
|
```
|
|
|
|
---
|
|
|
|
## RESOURCE ALLOCATION (2-3 Engineers)
|
|
|
|
### Engineer 1: Core Workflows
|
|
- Tasks: 1.1-1.4 (Foundation)
|
|
- Tasks: 2.1-2.5 (LLM-Router)
|
|
- Tasks: 3.1-3.6 (RoutingWorkflow)
|
|
|
|
### Engineer 2: API/CLI/Testing
|
|
- Tasks: 4.1-4.4 (API/CLI)
|
|
- Tasks: 5.1-5.4 (Testing)
|
|
- Tasks: 6.1-6.4 (Documentation)
|
|
|
|
### Both Engineers
|
|
- Daily sync on blockers
|
|
- Pair programming for complex tasks (2.3, 3.4)
|
|
- Code reviews
|
|
|
|
---
|
|
|
|
## SUCCESS CRITERIA (Acceptance for Each Phase)
|
|
|
|
**Phase 1**: All types compile, KB loads, validator catches errors ✅
|
|
**Phase 2**: llm-router generates valid specs, detects cron ✅
|
|
**Phase 3**: RoutingWorkflow executes any spec, handles errors ✅
|
|
**Phase 4**: API/CLI functional, all endpoints work ✅
|
|
**Phase 5**: >90% test coverage, all scenarios pass ✅
|
|
**Phase 6**: Complete documentation, can deploy ✅
|
|
|
|
---
|
|
|
|
## BLOCKERS TO WATCH
|
|
|
|
1. **LLM Integration** (Task 2.3)
|
|
- Need: Memory service API working
|
|
- Risk: LLM quality
|
|
- Mitigation: Test with real LLM early
|
|
|
|
2. **Temporal Cron Support** (Task 3.4)
|
|
- Need: CronSchedule in StartWorkflowOptions
|
|
- Risk: Version compatibility
|
|
- Mitigation: Verify Temporal SDK version
|
|
|
|
3. **Activity Registration** (Task 3.5)
|
|
- Need: All activities implemented
|
|
- Risk: Missing activities
|
|
- Mitigation: Create stub activities first
|
|
|
|
4. **Performance** (Task 5.4)
|
|
- Need: <200ms submit latency
|
|
- Risk: RoutingWorkflow overhead
|
|
- Mitigation: Profile early and often
|
|
|
|
---
|
|
|
|
## DELIVERABLES
|
|
|
|
### Code Deliverables
|
|
- ✅ internal/routing/ (types, validators, executors)
|
|
- ✅ statemachine/routing_workflow.go
|
|
- ✅ cmd/worker/activities/llm_router.go
|
|
- ✅ cmd/api-server/ (full HTTP server)
|
|
- ✅ cmd/cli/ (full CLI)
|
|
- ✅ tests/ (unit, integration, e2e, load tests)
|
|
|
|
### Documentation Deliverables
|
|
- ✅ docs/API.md
|
|
- ✅ docs/CLI.md
|
|
- ✅ docs/DEPLOYMENT.md
|
|
- ✅ docs/USER_GUIDE.md
|
|
- ✅ docs/examples/ (10+ workflow examples)
|
|
|
|
### Operational Deliverables
|
|
- ✅ internal/routing/activity_knowledge_base.json
|
|
- ✅ k8s/api-server-deployment.yaml
|
|
- ✅ Docker image for api-server
|
|
|
|
---
|
|
|
|
## DONE CRITERIA
|
|
|
|
- [ ] All code compiles without warnings
|
|
- [ ] All tests pass (unit, integration, e2e, load)
|
|
- [ ] >90% code coverage
|
|
- [ ] Documentation complete
|
|
- [ ] Can deploy to Kubernetes
|
|
- [ ] Can submit workflow from API/CLI
|
|
- [ ] Can create cron workflow
|
|
- [ ] Performance targets met
|
|
- [ ] No critical bugs
|
|
|
|
This is **ready to implement**! 🚀
|
|
|