fix(linkedin): prevent false block on profile prose containing "challenge" - #204
Merged
Merged
Conversation
…enge"
LinkedIn profile imports were failing with `rate_limited_or_blocked` for
users whose profile bio mentioned "challenge" or "checkpoint" (e.g. "I
enjoy new challenges"). The DOM block detector greedily scanned the
entire page `innerText` for those bare words and treated any match as a
challenge interstitial.
Root cause: `blockedReasonFromText` matched bare "challenge"/"checkpoint"
against `document.body.innerText`, which fires on legitimate profile prose.
Fix:
- Remove the greedy bare-word check. Only challenge-page-specific phrases
qualify as block signals ("security verification", "unusual activity",
"verify your identity", "security check", "temporarily restricted").
- Add a `hasProfileSections` guard: text-based block signals are
authoritative only when no profile sections (headline, experiences,
education) were found. A page that yielded real sections is never
treated as blocked on text alone.
- Fall back to `textContent` when `innerText` is undrawn (jsdom / edge
layouts) so the guard still works in tests.
Real `/checkpoint/` and `/challenge/` URL redirects are still caught
earlier by `classifyLinkedInUrl`, so genuine interstitials still block.
Model: updated `linkedin-import.model.md` (source of truth) with the
detection strategy and invariant #7.
Tests: added `linkedin-dom.test.ts` (4 cases) covering challenge-in-bio,
unusual-activity-in-profile, security-verification interstitial, and
checkpoint-in-prose.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
There was a problem hiding this comment.
Pull request overview
This PR fixes false-positive LinkedIn “checkpoint/challenge” blocking during CV/profile imports by making DOM-based block detection phrase-specific (instead of scanning for bare words like “challenge”/“checkpoint”) and by only trusting those text signals when no real profile sections were parsed. It also updates the LinkedIn import model doc to capture the refined detection strategy and adds unit coverage to prevent regressions.
Changes:
- Remove greedy bare-word
"challenge"/"checkpoint"DOM text checks and keep only challenge-page-specific phrases as block signals. - Add a
hasProfileSectionsguard so text-based block detection only applies when no headline/experience/education was extracted. - Add focused unit tests covering the prior false-positive scenarios and document the invariant in the model.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| apps/extension/src/lib/shell/profile-extractors/linkedin.extractor.ts | Refines DOM “blockedReason” detection to be phrase-specific and gated by presence of parsed profile sections. |
| apps/extension/tests/unit/profile-extractors/linkedin-dom.test.ts | Adds regression tests ensuring normal bios containing “challenge/checkpoint/unusual activity” don’t trigger blocked imports, while real interstitial text still does. |
| apps/extension/src/models/linkedin-import.model.md | Documents the updated block-detection strategy and adds an explicit invariant to prevent reintroducing greedy text matching. |
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
rate_limited_or_blockedwhenever the profile bio contained the bare words "challenge" or "checkpoint" (e.g. "I enjoy new challenges"). The DOM block detector greedily scanned the entire pageinnerTextfor those words and treated any match as a security interstitial, blocking real imports.hasProfileSectionsguard so text-based block signals are authoritative only when no profile sections (headline, experiences, education) were found. A page that yielded real sections is never treated as blocked on text alone./checkpoint/and/challenge/URL redirects are still caught earlier byclassifyLinkedInUrl, so genuine interstitials still block.linkedin-import.model.md(source of truth) with the detection strategy and invariant "ux(settings): replace alert() and reload with toasts and controlled state refresh" #7, per the Model -> Review -> Implement -> Verify workflow.Verification
pnpm format:checkpnpm lintpnpm typecheckpnpm testpnpm buildNote: 1708 unit tests pass. The 15
tests/unit/ui/*suites that fail in a cold workspace are pre-existing and caused by@pulse/uinot being built; they pass oncepnpm --filter @pulse/ui buildruns (verified). Unrelated to this change.Checklist