diff options
| author | Claudomator Agent <agent@claudomator.local> | 2026-03-24 22:32:57 +0000 |
|---|---|---|
| committer | Claudomator Agent <agent@claudomator.local> | 2026-03-24 22:32:57 +0000 |
| commit | dfadaf89a4dd71389dec9e0e15acd09477f18c2b (patch) | |
| tree | 7f422ef845736f5f325e353b5234adf1458863bb /internal/executor/executor.go | |
| parent | 8b1a710b655994f8ffb5747422088de5b88572e1 (diff) | |
feat: validation result transitions story to REVIEW_READY or NEEDS_FIX (ADR-007)
Add checkValidationResult which inspects the final task.State of a
completed validation task and updates the story to REVIEW_READY (pass)
or NEEDS_FIX (fail). Wire into handleRunResult so stories in
VALIDATING state are dispatched to checkValidationResult instead of
checkStoryCompletion, covering both success and FAILED terminal paths.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'internal/executor/executor.go')
| -rw-r--r-- | internal/executor/executor.go | 45 |
1 files changed, 44 insertions, 1 deletions
diff --git a/internal/executor/executor.go b/internal/executor/executor.go index 745c6d6..c5a1fce 100644 --- a/internal/executor/executor.go +++ b/internal/executor/executor.go @@ -376,6 +376,19 @@ func (p *Pool) handleRunResult(ctx context.Context, t *task.Task, exec *storage. } } } + if t.StoryID != "" && exec.Status == "FAILED" { + storyID := t.StoryID + errMsg := exec.ErrorMsg + go func() { + story, getErr := p.store.GetStory(storyID) + if getErr != nil { + return + } + if story.Status == task.StoryValidating { + p.checkValidationResult(ctx, storyID, task.StateFailed, errMsg) + } + }() + } } else { p.mu.Lock() p.consecutiveFailures[agentType] = 0 @@ -405,7 +418,19 @@ func (p *Pool) handleRunResult(ctx context.Context, t *task.Task, exec *storage. p.maybeUnblockParent(t.ParentTaskID) } if t.StoryID != "" { - go p.checkStoryCompletion(ctx, t.StoryID) + storyID := t.StoryID + go func() { + story, getErr := p.store.GetStory(storyID) + if getErr != nil { + p.logger.Error("handleRunResult: failed to get story", "storyID", storyID, "error", getErr) + return + } + if story.Status == task.StoryValidating { + p.checkValidationResult(ctx, storyID, task.StateCompleted, "") + } else { + p.checkStoryCompletion(ctx, storyID) + } + }() } } @@ -540,6 +565,24 @@ func (p *Pool) createValidationTask(ctx context.Context, storyID string) { p.Submit(ctx, vtask) //nolint:errcheck } +// checkValidationResult inspects a completed validation task and transitions +// the story to REVIEW_READY or NEEDS_FIX accordingly. +func (p *Pool) checkValidationResult(ctx context.Context, storyID string, taskState task.State, errorMsg string) { + if taskState == task.StateCompleted { + if err := p.store.UpdateStoryStatus(storyID, task.StoryReviewReady); err != nil { + p.logger.Error("checkValidationResult: failed to update story status", "storyID", storyID, "error", err) + return + } + p.logger.Info("story transitioned to REVIEW_READY", "storyID", storyID) + } else { + if err := p.store.UpdateStoryStatus(storyID, task.StoryNeedsFix); err != nil { + p.logger.Error("checkValidationResult: failed to update story status", "storyID", storyID, "error", err) + return + } + p.logger.Info("story transitioned to NEEDS_FIX", "storyID", storyID, "error", errorMsg) + } +} + // UndrainingAgent resets the drain state and failure counter for the given agent type. func (p *Pool) UndrainingAgent(agentType string) { p.mu.Lock() |
