61 lines
1.7 KiB
Go
61 lines
1.7 KiB
Go
package domain
|
|
|
|
import (
|
|
"errors"
|
|
|
|
contract "git.cin.su/m/Assistant/contracts/situation"
|
|
"git.cin.su/m/Assistant/contracts/work"
|
|
)
|
|
|
|
var (
|
|
ErrNoActiveFocus = errors.New("no active focus binding")
|
|
ErrStaleFocus = errors.New("stale focus binding")
|
|
ErrAmbiguousFocus = errors.New("ambiguous focus binding")
|
|
ErrTargetMismatch = errors.New("proposed target does not match resolved focus")
|
|
)
|
|
|
|
// Resolver is a deterministic situation-owned resolver. It accepts runtime
|
|
// bindings only; RequestText must never be used to select a project.
|
|
type Resolver struct {
|
|
bindings []contract.FocusBinding
|
|
}
|
|
|
|
func NewResolver(bindings []contract.FocusBinding) Resolver {
|
|
return Resolver{bindings: append([]contract.FocusBinding(nil), bindings...)}
|
|
}
|
|
|
|
func (r Resolver) Resolve(runtime contract.RuntimeBinding) (contract.FocusBinding, error) {
|
|
var matches []contract.FocusBinding
|
|
var stale bool
|
|
for _, binding := range r.bindings {
|
|
if binding.SessionID != runtime.SessionID || binding.Workspace != runtime.Workspace {
|
|
continue
|
|
}
|
|
if !binding.Active {
|
|
stale = true
|
|
continue
|
|
}
|
|
matches = append(matches, binding)
|
|
}
|
|
switch len(matches) {
|
|
case 0:
|
|
if stale {
|
|
return contract.FocusBinding{}, ErrStaleFocus
|
|
}
|
|
return contract.FocusBinding{}, ErrNoActiveFocus
|
|
case 1:
|
|
return matches[0], nil
|
|
default:
|
|
return contract.FocusBinding{}, ErrAmbiguousFocus
|
|
}
|
|
}
|
|
|
|
// ValidateTaskTarget prevents cognition from redirecting a request outside the
|
|
// resolved situation before a work owner considers its own revision guard.
|
|
func ValidateTaskTarget(focus contract.FocusBinding, target work.TaskTarget) error {
|
|
if focus.GoalID != target.GoalID || focus.ScopeID != target.ScopeID {
|
|
return ErrTargetMismatch
|
|
}
|
|
return nil
|
|
}
|