fix(search): honor UTC+0 timezone offset instead of collapsing to default -7 - #55
Merged
tylermenezes merged 1 commit intoSep 18, 2026
Conversation
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.
Detail bug report: View on Detail
Bug
TIMEZONE_MATCH(15×) is the single largest weight in thegetProjectMatchesranking query. The timezone offset wrapper insrc/search/ElasticEntry.tsand its query-side mirror insrc/search/getProjectMatches.tsboth passed the innergetTimezoneOffsetresult through a JS falsy check (if (basicLookup)and|| -7).The inner util (
src/utils/getTimezoneOffset.ts) returnsnullfor unrecognized zones but a legitimate0(or-0, depending on ICU) for UTC+0 zones —Atlantic/Reykjavik,Africa/Accra,GMT,UTC, etc. Since0and-0are falsy, UTC+0 mentors and students were silently collapsed to the-7default — the same index bucket asAsia/Bangkok(UTC+7). This shifted the ±4h timezone boost window eastward and awarded the 15× multiplier to mentors 7–11h east of the student while denying it to mentors genuinely within ±4h, producing a systematic eastward skew in match ranking for any UTC+0 user.Fix
Distinguish
null(unrecognized) from a valid numeric zero on both paths — both must change together, or a UTC+0 mentor (indexed at0) would stop matching a UTC+0 student (still queried at-7):src/search/ElasticEntry.ts:if (basicLookup) return basicLookup;→if (basicLookup !== null) return basicLookup;, and the legacy-string-dict fallback[...] || -7→[...] ?? -7.src/search/getProjectMatches.ts:getTimezoneOffset(student.timezone) || -7→getTimezoneOffset(student.timezone) ?? -7.This is the idiomatic fix because it matches the inner util's
null-as-"unrecognized" sentinel contract and honors both signs of zero (-0 !== nulland+0 !== null), so it's correct regardless of which ICU version produces which sign.Testing
src/search/searchTimezone.test.ts(following the repo's existing hand-rolledassert/assertEqualstyle), covering: the inner util's0-vs-nullcontract; the indexing path viaprojectToElasticEntry(UTC+0 →0, real non-zero offsets unchanged, missing/unrecognized →-7, legacySGTdict fallback →8); the query-side boost window read out of the generated Elasticsearch query JSON via typedi-injected fakes (UTC+0 student →[-4..4], real UTC+7 student →[-11..-3], unrecognized/missing →-7); and an end-to-end ranking test that scores two otherwise-equal mentors against the real generated function-score. All assertions pass; a pre-fix run of the same suite reproduces the bug (UTC+0 →-7; window[-11..-3]).tsc --skipLibCheck --noEmit) and the pre-existing offline suite (syncAlumniInteractions.test.ts) both still pass.Africa/Lagos, real UTC+7Asia/Bangkok), bulk-indexed via the realelasticSynctask, and confirmed a UTC+0 student ranks the UTC+1 mentor above the UTC+7 mentor (scores75vs5, the 15× timezone multiplier landing on the correct mentor), while a UTC+7 student still ranks the UTC+7 mentor first.Europe/London,Europe/Lisbon, etc.) but could not confirm the=== 0assertion at this date — they're currently on summer time (offset-1). The fix honors both+0and-0, the two falsy signs of zero, so the winter case is covered by the same mechanism verified for the year-round UTC+0 zones.@typescript-eslint/parser@3.x(via@codeday/eslint-typescript-config@2.1.5), which is incompatible with the installedtypescript@5.2.2and fails to parse every file in the tree withDeprecationError: 'originalKeywordKind'. This is a pre-existing toolchain issue unrelated to this change.Automatic Fixes PRs can be configured here.