54 lines
1.5 KiB
Go
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
|
|
}
|