Files
dobotai-platform/internal/coverage/service.go
2026-07-22 12:48:30 +08:00

54 lines
1.5 KiB
Go

package coverage
import (
"context"
"errors"
"fmt"
"gitea.zheromiku.top/Weknora/dobotai-platform/internal/core"
)
// Service evaluates turns and persists coverage decisions.
type Service struct {
evaluator *Evaluator
repo Repository
}
// NewService creates a coverage Service. repo must not be nil.
func NewService(repo Repository) (*Service, error) {
if repo == nil {
return nil, errors.New("coverage service: repository must not be nil")
}
return &Service{
evaluator: NewEvaluator(),
repo: repo,
}, nil
}
// ObserveSucceededTurn adapts Service to the QA succeeded-turn observer.
// The decision is persisted durably before QA returns; callers decide how to
// report the error without changing the successful QA result.
func (s *Service) ObserveSucceededTurn(ctx context.Context, turn core.Turn) error {
_, err := s.EvaluateAndPersist(ctx, turn)
return err
}
// EvaluateAndPersist evaluates a turn and persists the resulting decision.
// For uncovered verdicts the Repository atomically creates a pending
// support case. The operation is idempotent — replaying the same
// (tenant_key, channel, turn_id) is safe.
//
// Failed and processing turns are rejected with ErrTurnNotSucceeded.
func (s *Service) EvaluateAndPersist(ctx context.Context, turn core.Turn) (Decision, error) {
d, err := s.evaluator.Evaluate(turn)
if err != nil {
return Decision{}, fmt.Errorf("evaluate: %w", err)
}
if err := s.repo.SaveCoverageDecision(ctx, d); err != nil {
return Decision{}, fmt.Errorf("save coverage decision: %w", err)
}
return d, nil
}