feat(engine): scoring engine with normalised-distance match#3
Merged
Conversation
Pure-function package, no runtime deps. Vitest with 100% coverage thresholds, tsconfig extending the shared base, and framework-free engine types that reuse the shared domain shapes (type-only).
- evaluateVisibility: and/or condition groups; operators equals, not_equals, greater_than, less_than, contains (string + string[]), empty. Absent/empty rule = visible. - scoreAnswers: per-category sum of chosen options' scores over visible questions only. - computeResults: normalised-distance match% (range = max achievable per category, auto-derived), averaged over the result's target categories, clamped to [0,100]; hard exclusions flagged and sunk; stable sort. Developed test-first; 100% line/branch/function coverage.
Add a turbo 'test' task and root 'test' script, and a Test step in the CI workflow so engine coverage is gated on every PR.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
@matchachoice/engine— a framework-free, zero-runtime-dependency package with the v1 scoring logic. Type-only imports of the shared domain shapes from@matchachoice/db/schema/types.Three pure functions:
evaluateVisibility(rule, answers)—and/orcondition groups; operatorsequals,not_equals,greater_than,less_than,contains(string + multiple-choicestring[]),empty. Absent/empty rule = visible.scoreAnswers(check, answers)— per-category sum of the chosen options' scores, over visible questions only.computeResults(check, answers)— normalised-distance match%, hard exclusions, descending stable sort. Returns{ resultId, matchPct, excluded }[].Match% algorithm
dist_c = |userScore_c − target_c| / range_crange_c= max achievable score per category, auto-derived from the check definition (sum of the highest option score per question). Not configurable.match% = 100 × (1 − avg(dist_c)), averaged only over the result's target categories, clamped to[0, 100].range_c = 0→ category skipped. No averageable category →match% = 0.Hard exclusions
A matching
exclusionrule flags the resultexcluded: true, keeps its match%, and sinks it below all non-excluded results (not dropped — the caller decides). Empty/absent exclusion never excludes.Tests / DoD
and/orcombinations, multiple-choice (string[]) forcontains+ scoring, missing/empty answers, category with max=0 (skip), result without targets, all results excluded, stable tie ordering, over-range clamp.pnpm check,pnpm check-types,pnpm test,SKIP_ENV_VALIDATION=1 pnpm build— all green locally.testtask + roottestscript + a CITeststep so coverage is gated on every PR.Notes for reviewer
RankedResultkeeps excluded results (flagged) rather than filtering them — the field would be meaningless otherwise.match% = 0; the sharedRuleGrouptype is flat, so true nested groups are out of scope for v1.