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 }