package matching import ( "context" "github.com/shopspring/decimal" "github.com/missionworkforce/missionmatch/internal/modules/matching/engine" ) // compile-time assertion that ChainedResolver satisfies engine.SkillMatcher. var _ engine.SkillMatcher = (*ChainedResolver)(nil) // ChainedResolver runs the deterministic alias and relationship resolver first, then the semantic // matcher, and satisfies the engine SkillMatcher interface so the engine code is unchanged. // The resolver is consulted first because curated ontology knowledge (an alias is an exact // equivalence; a verified substitution has a known strength) is more precise and auditable than a // cosine similarity. The semantic matcher runs only when the resolver finds no match. type ChainedResolver struct { resolver *DeterministicAliasResolver semantic engine.SkillMatcher } // NewChainedResolver builds a ChainedResolver from a DeterministicAliasResolver and a semantic // SkillMatcher. Either may be nil: a nil resolver skips the alias step, a nil semantic falls back // to resolver only (or no match when the resolver also misses). func NewChainedResolver(resolver *DeterministicAliasResolver, semantic engine.SkillMatcher) *ChainedResolver { return &ChainedResolver{resolver: resolver, semantic: semantic} } // Match satisfies engine.SkillMatcher. It returns the best candidate skill satisfying the required // skill. The alias resolver runs first; on a hit the result is returned immediately and the semantic // matcher is never called. On a resolver miss, the semantic matcher runs at the given threshold. // ctx carries the request deadline and cancellation to both the resolver and any semantic provider call. func (c *ChainedResolver) Match( ctx context.Context, required engine.RequiredSkill, cands []engine.CandidateSkill, threshold decimal.Decimal, ) (engine.SkillMatch, bool) { if c.resolver != nil { if m, ok := c.resolver.ResolveAlias(ctx, required, cands); ok { return m, true } } if c.semantic == nil { return engine.SkillMatch{}, false } return c.semantic.Match(ctx, required, cands, threshold) }