Match "North Kerby Avenue" to "N Kerby Ave." when deduplicating #2

Merged
forgejo-admin merged 2 commits from fix/address-normalisation into main 2026-09-08 02:26:23 +00:00

Problem

The 2026 form has its first real response and it reads "3704 North Kerby Avenue". The 2025 export has "3704 N Kerby Ave." for the same house.

addressKey lower-cased and squashed whitespace, so those were two different keys. Consequences: the deduplication misses and the map grows a second pin on a house that signed up once, and the geocoder is called again for an address already in the cache.

Found by rendering the site against the real published sheet instead of the 2025 fixture.

Solution

addressKey maps spelled-out directions and street types onto their abbreviations before keying, so both spellings collapse to 3704 n kerby ave. A direction word that is also part of a street name still survives — 100 N North Ave and 100 N Ave stay distinct, and there's a test for it.

The geocode cache is re-keyed to the same normal form. Two of its 34 entries moved (375 northeast shaver street apt 502, 750 n fremont street). Re-running the pipeline against the 2025 CSV makes zero network calls, so nothing was orphaned.

Verification

  • bunx tsc --noEmit clean
  • bun test — 13 pass, 0 fail
  • The four new tests were run against the old implementation first and 2 of them failed, on exactly the two conversions. A gate nobody has seen fail is not a gate.
  • bun run convert-csv still keeps 33 sales and drops the same 2, with no geocoding

🤖 Generated with Claude Code

https://claude.ai/code/session_01PyCzDSqUNGDS5W3bznaQW5

## Problem The 2026 form has its first real response and it reads **"3704 North Kerby Avenue"**. The 2025 export has **"3704 N Kerby Ave."** for the same house. `addressKey` lower-cased and squashed whitespace, so those were two different keys. Consequences: the deduplication misses and the map grows a second pin on a house that signed up once, and the geocoder is called again for an address already in the cache. Found by rendering the site against the real published sheet instead of the 2025 fixture. ## Solution `addressKey` maps spelled-out directions and street types onto their abbreviations before keying, so both spellings collapse to `3704 n kerby ave`. A direction word that is also part of a street name still survives — `100 N North Ave` and `100 N Ave` stay distinct, and there's a test for it. The geocode cache is re-keyed to the same normal form. Two of its 34 entries moved (`375 northeast shaver street apt 502`, `750 n fremont street`). Re-running the pipeline against the 2025 CSV makes **zero network calls**, so nothing was orphaned. ## Verification - `bunx tsc --noEmit` clean - `bun test` — 13 pass, 0 fail - The four new tests were run against the *old* implementation first and 2 of them failed, on exactly the two conversions. A gate nobody has seen fail is not a gate. - `bun run convert-csv` still keeps 33 sales and drops the same 2, with no geocoding 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01PyCzDSqUNGDS5W3bznaQW5
The 2026 form already has its first real response, and it reads "3704
North Kerby Avenue". The 2025 export has "3704 N Kerby Ave." for the same
house. addressKey lower-cased and squashed whitespace but treated those as
two different addresses, so the deduplication would have missed and the map
would have grown a second pin on a house that signed up once. It would also
have re-geocoded an address already in the cache.

addressKey now maps spelled-out directions and street types onto the
abbreviations before keying, so the two forms collapse. A direction that is
also part of a street name still survives, which the tests cover.

The geocode cache is re-keyed to the same normal form. Two of its 34 entries
moved ("375 northeast shaver street apt 502" and "750 n fremont street"),
and re-running the pipeline against the 2025 CSV makes zero network calls,
so nothing was orphaned.

Verified the tests fail against the old implementation before they passed
against the new one: two of them, on exactly the two conversions.

Found by rendering the site against the real published sheet rather than
the 2025 fixture. Same run surfaced two copy defects in the mock, fixed
there: a street name that came out "North kerby", and a tally that said
"1 sales".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PyCzDSqUNGDS5W3bznaQW5
Follow-on to the address normalisation in this branch. Review asked whether
two spellings of one address would geocode to the same place and whether we
should just drop anything that overlaps in space.

They would, and we should not. A shared point means one house typed two
ways, but it just as often means a duplex, an apartment building, or a house
and the ADU behind it, where the neighbours really are selling separately.
Dropping on position would silently delete a real listing. The address stays
the identity; position is a derived approximation, so a collision is a prompt
for the operator rather than grounds for deletion.

findStackedPins groups entries by coordinates rounded to six places, about
ten centimetres, so only a true collision is reported. The run prints the
groups after the drop report and says plainly that nothing was removed.

Run against the 2025 data it immediately finds a real one: "3720 N Michigan
Ave" and "3720 N Michigan Ave / Alley Garage" are two listings at one
address, and whether that is one household or a house plus its alley garage
is exactly the judgement a person has to make.

Four tests, including that neighbours a few metres apart are not grouped and
that three units at one point come back as one group. Verified they fail
against a stub returning [] before they passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018fVMptFeMs2vUR31ByWYYF
forgejo-admin deleted branch fix/address-normalisation 2026-09-08 02:26:23 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
celilo/bna-yard-sale!2
No description provided.