Agent Match
Tested · CI green · not deployed, no users · private repository
Summary
Agent Match ranks licensed rental agents for one specific property, using evidence the platform can check: license status, listing history near the property, and how confidently each listing is tied to the agent. The most instructive engineering is in what it refuses to do. It will not merge two agents on a name match, will not show a score without enough data behind it, and will not count data it has no right to use.
The problem and who it serves
Landlords choosing a rental agent mostly see ads, star ratings and self-reported claims. Agent Match asks a narrower question: which licensed agents have checkable rental activity near this property, and how far can that evidence be trusted?
Landlords with a rental in Staten Island who want a licensed agent; agents, who can claim and manage their own profile; and administrators, who review uncertain identity matches. There is no hosted instance and there are no users.
My role
Solo. I owned the product definition, the evidence model, the data-source and data-rights decisions, and the review of every change. Implementation was AI-assisted under my direction across 59 commits between 2026-07-30 and 2026-09-07, with test, typecheck and build results recorded as the work went.
Architecture
2 · scoring on that bounded set→PostgreSQL 17 + PostGISPrisma 6 · 20 migrations
The diagram is drawn from the code. The scoring engine is a separate package with no database or framework dependency, so every rule in it is unit-tested as a pure function. The web app owns persistence and turns scores into the three evidence tiers a landlord sees.


Decisions and trade-offs
- Never merge two people on a name. Identity signals are weighted in one config: a licence number or an already-linked ID scores 100, verified email 90, phone 85, but an exact name only 30 and a shared brokerage 25. Auto-linking needs 85 and review needs 40, so a name alone clears neither; two candidates within 10 points of each other always go to review. The cost is real and accepted: in the August 2026 live import, plausible matches scored about 65 and sat in the review queue, so no listing yet has a human-confirmed agent.
- Say “limited verified data” instead of showing a number. Scores are shrunk toward a neutral prior by sample size, so two lucky rentals cannot outrank a long record, and an agent with very low confidence and no local evidence gets no score at all. Results are grouped into verified rental performance, verified local activity and nearby licensed agents, which also fixed an earlier release-blocking bug where honest filtering returned zero results. A related bug was found and fixed during testing: the profile page invented a performance score for agents with no completed rentals.
- Push geography into the database, then measure the planner. Candidate search runs as a PostGIS distance query instead of loading every listing. According to the project’s own notes from July 2026 (commit c8277ff), EXPLAIN ANALYZE showed the planner expected about one matching row when nearly all rows matched, so it chose a nested-loop join: 1.8 s and 15.6 million row pairs. Disabling nested loops for that one transaction only produced a hash join at 25 ms. The trade-off is a planner hint, kept as narrow as possible and documented.
- Put data rights in code. Each source has an explicit usage policy. The MLS integration (adapter, sync jobs, identity rules and admin views) is complete but gated twice, by a feature flag and by scoring eligibility, so a misconfigured flag still cannot count data the project has no agreement to use.
Verified results
| Measure | Result | Evidence |
|---|---|---|
| Package unit tests | 181 passed (data adapters 63, identity 77, scoring 41) | CI run 34135525138, main aa62fd6, 2026-09-07; rerun on a fresh clone 2026-10-24 |
| Web app tests on an isolated PostGIS test database | 116 passed in 16 files | Same CI run and local rerun. Most query the database; a few cover pure helpers such as redirect safety |
| Browser end-to-end tests (Playwright, historical) | 64 passed: 32 tests on desktop and mobile Chromium | CI run 34135525138 only (2026-09-07), against the synthetic seed database. Not rerun since |
| CI on main | red since 2026-08-03 → green | Commit 7a150cf: admin pages looped between /admin and /login for signed-in non-admins. An existing end-to-end test already described the intended behaviour |
| Core geographic query (historical) | 1.8 s → 25 ms | Recorded in the project’s scoring documentation with commit c8277ff (2026-07-30): EXPLAIN ANALYZE before and after on the synthetic dataset. Not reproduced for this page |
| Synthetic demo dataset | 104 agents, 3,954 listings, deterministic seed | Local run 2026-10-24; fictional names, example.com addresses and reserved 555-01xx numbers |
Limitations and remaining work
- Not deployed, no users. The Docker Compose path has never been run; development used a hand-initialised PostgreSQL 17 + PostGIS.
- The August 2026 live import (2,279 licensed agents, 4,399 listings and 360 brokerages from public licensing records and a listings API) lived in a local database that was later lost. Those figures come from the project’s own records and cannot be re-checked; restoring them means re-running the imports with a listings API key.
- No listing has a human-confirmed agent identity yet. Real records share only name, brokerage and ZIP, which by design is not enough to auto-link.
- Found while preparing this page: a results card scores an agent from listings inside the search radius, while the profile uses the agent’s full history. Both use the label “verified rental performance”, so one agent can show different numbers in two places. Not fixed yet.
- The MLS adapter is shaped to the published data standard but has never seen a real response. It stays disabled until a data agreement exists.
- Statistics are recomputed from raw listings on every request; the precomputed tables exist but are not wired in. Also open: sign-up CAPTCHA, error monitoring, duplicate-agent merge tooling, brokerage alias resolution, object storage for photos and phone verification.