career/qwestly/2026-10-existing-member-profile-cleanup.md
Table of Contents
Cleared duplicate and undated saved roles blocking existing members' briefing
Situation
Before inviting existing members into the new briefing, a census of production found 49 of the 193 real members with saved roles holding the same job more than once (129 extra rows), so the agent asked "which of these saved roles is it?" between identical options. Worse, 17 members had legacy roles with no start date, which made the profile write path reject every edit to their experience, the briefing's answers included, silently.
What I did
- Ran the census, then cleaned every affected member through the one sanctioned write path
(
updateProfile()), never a raw database write, so derived fields and the search index stayed in sync: dry-run-by-default tooling, a local rehearsal on a production copy, canaries first, per-member pre-images, version-guarded writes. - Used the same copy rule the new matcher ships with (qwestly-agent#350), so "duplicate" means one thing in code and in data.
- When 9 members stayed blocked, traced every undated row to its source through a June production backup: old rรฉsumรฉ/bio parsers and one voice-interview mis-transcription. Several rows that looked like real missing jobs turned out to be copies under another spelling.
- Judgment calls: held members whose "current job" would vanish for a product decision; added their real current job from LinkedIn where it was missing, instead of leaving them blank.
- Found and documented the write-path bug (legacy undated rows block all edits) and the related scenario gaps for the briefing stress test.
Result
Duplicate saved roles went from 49 members (129 rows) to 0, in production, with no change to any member's current title except 3 whose "current" role had been an undated copy of an ended job (now corrected). Members whose experience edits could not be saved: 17 โ 0, with 29 dated roles restored from LinkedIn where the old interview pipeline had saved them undated.
Metrics
| Metric | Baseline (2026-09-30/10-01) | Target | Latest (2026-10-01) |
|---|---|---|---|
| Real members with a duplicated saved role | 49 / 193 with roles (129 extra rows) | 0 | 0 |
| Real members with an undated role (edits blocked) | 17 (51 roles) | 0 | 0 |
| Members wrongly shown a stale "current" job from an undated copy | 3 | 0 | 0 |
How to measure
Workspace _docs/existing-member-cleanup/verify.py check production (copy groups among real
members, via #350's roles_are_copies), and a count of real members' candidate_profile
documents with an experience entry whose start is empty or missing. Population: candidate
profiles with a member record and an email, minus internal and test addresses (plan ยง3.1).
Log
- 2026-09-30: census baseline (49 members, 129 copy rows).
- 2026-10-01: 40 members cleaned; 9 blocked by the undated-row bug; traced and cleaned all 9. 0 copy groups. 8 other members still hold undated roles.
- 2026-10-01: traced the remaining 8 (mostly the old voice-interview step) and cleaned them; 27 dated LinkedIn roles added. 0 undated roles left among real members.