Skip to content

fix(linkedin): prevent false block on profile prose containing "challenge" - #204

Merged
guyghost merged 1 commit into
developfrom
guyghost-fix-linkedin-false-block-detection
Jul 9, 2026
Merged

fix(linkedin): prevent false block on profile prose containing "challenge"#204
guyghost merged 1 commit into
developfrom
guyghost-fix-linkedin-false-block-detection

Conversation

@guyghost

@guyghost guyghost commented Jul 9, 2026

Copy link
Copy Markdown
Owner

Summary

  • LinkedIn CV imports were failing with rate_limited_or_blocked whenever the profile bio contained the bare words "challenge" or "checkpoint" (e.g. "I enjoy new challenges"). The DOM block detector greedily scanned the entire page innerText for those words and treated any match as a security interstitial, blocking real imports.
  • Removed the greedy bare-word check: only challenge-page-specific phrases now qualify as block signals ("security verification", "unusual activity", "verify your identity", "security check", "temporarily restricted").
  • Added a hasProfileSections guard 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.
  • Real /checkpoint/ and /challenge/ URL redirects are still caught earlier by classifyLinkedInUrl, so genuine interstitials still block.
  • Updated 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:check
  • pnpm lint
  • pnpm typecheck
  • pnpm test
  • pnpm build

Note: 1708 unit tests pass. The 15 tests/unit/ui/* suites that fail in a cold workspace are pre-existing and caused by @pulse/ui not being built; they pass once pnpm --filter @pulse/ui build runs (verified). Unrelated to this change.

Checklist

  • No secrets, cookies, session tokens, or generated release artifacts committed
  • Core code remains pure; I/O stays in shell modules
  • Svelte changes use Svelte 5 runes only — N/A (no Svelte changes)
  • Documentation updated when behavior or setup changes

…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>
@vercel

vercel Bot commented Jul 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
pulse Ready Ready Preview, Comment Jul 9, 2026 5:47pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
pulse-dashboard Skipped Skipped Jul 9, 2026 5:47pm

Copilot AI review requested due to automatic review settings July 9, 2026 17:47
@guyghost
guyghost merged commit a0a7fc4 into develop Jul 9, 2026
8 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 hasProfileSections guard 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants