[REFAC#148] LinkDiscovery ArticleURLPattern optional + 사이트 rule all-pass 전환 - #150
Conversation
|
Warning Rate limit exceeded
To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughMake Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Warning Review ran into problems🔥 ProblemsTimed out fetching pipeline failures after 30000ms Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Review rate limit: 0/1 reviews remaining, refill in 46 minutes and 36 seconds.Comment |
There was a problem hiding this comment.
Code Review
This pull request implements an 'all-pass' mode for link discovery, enabling the crawler to capture all links when ArticleURLPattern is empty. It includes logic updates to skip regex filtering, refined exclusion patterns in database migrations for major news sites, and updated unit tests. Feedback indicates that related documentation in LinkDiscoveryConfig should be updated to reflect these changes and that a comment in the migration script incorrectly describes the same_origin_only setting.
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
internal/crawler/parser/rule/parser.go (1)
163-170:⚠️ Potential issue | 🟡 MinorUpdate the fallback error text to match the new routing.
This branch now runs only when
LinkDiscoveryis nil, so pointing operators atLinkDiscovery.ArticleURLPatternis misleading. If they hit this error, they need the wholelink_discoveryblock, not just the pattern field.Proposed text tweak
- Message: "list rule missing required ItemContainer or ItemLink selector (or set LinkDiscovery.ArticleURLPattern)", + Message: "list rule missing required ItemContainer or ItemLink selector (or set LinkDiscovery)",🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/crawler/parser/rule/parser.go` around lines 163 - 170, The error message returned when both rule.Selectors.ItemContainer and rule.Selectors.ItemLink are missing (the Error with Code ErrEmptySelector) incorrectly points users to LinkDiscovery.ArticleURLPattern even though this branch only runs when LinkDiscovery is nil; update the Error.Message text to instruct operators to provide the full link_discovery block (not just ArticleURLPattern) so it accurately reflects the required configuration when LinkDiscovery is absent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@test/internal/parser/rule/discovery_test.go`:
- Around line 308-324: The test must prove ParseLinks used LinkDiscovery rather
than falling back to ItemContainer: modify
TestParser_ParseLinks_LinkDiscoveryWithEmptyPattern_AllPassDiscovery so the
fakeRepo or repo spy records/guards ItemContainer calls (e.g., have fakeRepo's
ItemContainer method panic or set a flag if invoked) and assert it was not
called after calling rule.NewParser(...).ParseLinks; alternatively make
r.Selectors.ItemContainer an impossible selector that cannot match listHTML so
only LinkDiscovery can produce the three links. Ensure you reference ParseLinks,
TestParser_ParseLinks_LinkDiscoveryWithEmptyPattern_AllPassDiscovery,
LinkDiscoveryConfig, fakeRepo and ItemContainer in the change.
- Around line 186-229: Extend the empty-pattern tests to assert that
PathPrefixes still filter links when ArticleURLPattern is disabled: in
TestPageLinkDiscovery_EmptyPattern_ExcludeStillApplies (or add a new similar
test) set cfg.PathPrefixes (e.g., []string{"/article/", "/news/"}) along with
ArticleURLPattern:"" and SameOriginOnly:true, call d.Discover(makeRaw(...), cfg)
and then assert that no returned item.URL has any of the configured
PathPrefixes; reference NewPageLinkDiscovery, Discover and
storage.LinkDiscoveryConfig to locate where to add this assertion.
---
Outside diff comments:
In `@internal/crawler/parser/rule/parser.go`:
- Around line 163-170: The error message returned when both
rule.Selectors.ItemContainer and rule.Selectors.ItemLink are missing (the Error
with Code ErrEmptySelector) incorrectly points users to
LinkDiscovery.ArticleURLPattern even though this branch only runs when
LinkDiscovery is nil; update the Error.Message text to instruct operators to
provide the full link_discovery block (not just ArticleURLPattern) so it
accurately reflects the required configuration when LinkDiscovery is absent.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 041050c3-adab-4a1c-b7af-2fb1ad4c76e1
📒 Files selected for processing (5)
internal/crawler/parser/rule/discovery.gointernal/crawler/parser/rule/parser.gomigrations/down/008_relax_link_discovery_patterns.sqlmigrations/up/008_relax_link_discovery_patterns.sqltest/internal/parser/rule/discovery_test.go
- pattern 비어있으면 regex compile 단계 skip → all-pass 모드 - ExcludePatterns + SameOriginOnly + PathPrefixes + MaxLinksPerPage 만으로 필터링 - 매칭 루프에서 pattern==nil 가드 추가 - 0건 매칭 메시지를 모드별로 분기 (pattern stale vs page-empty) 본 시스템 타겟이 article 만이 아닌 페이지 내 모든 의미 있는 글 (이슈 #100 도메인 일반화 의도) 이므로, 사이트별 좁은 article URL regex 강제는 비-article 컨텐츠 (공지/이벤트/시리즈/오피니언) 누락 야기. 본 commit 은 컴포넌트 레벨 변경만 — Parser 분기 + DB 시드 변경은 후속 commits 에서. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
기존: cfg != nil && cfg.ArticleURLPattern != "" → discovery 신규: cfg != nil → discovery (pattern 빈 문자열도 all-pass 모드로 진입) ItemContainer fallback 은 LinkDiscovery 객체 자체가 nil 일 때만 발동. 운영자가 LinkDiscovery 객체를 두면 명시적으로 discovery 모드 선택한 것으로 간주. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
기존: - TestPageLinkDiscovery_EmptyPattern_ReturnsEmptySelector — 빈 pattern → ErrEmptySelector expect - TestParser_ParseLinks_LinkDiscoveryWithEmptyPattern_FallsBackToItemContainer — 빈 pattern → ItemContainer 신규: - TestPageLinkDiscovery_EmptyPattern_AllPass — 빈 pattern → 모든 same-origin 링크 통과 + 기본 제외 패턴 (login/mailto 등) 차단 검증 - TestPageLinkDiscovery_EmptyPattern_ExcludeStillApplies — all-pass 모드에서 ExcludePatterns 동작 - TestParser_ParseLinks_LinkDiscoveryWithEmptyPattern_AllPassDiscovery — 빈 pattern + LinkDiscovery 객체 있음 → all-pass discovery (ItemContainer 사용 X) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ns 강화 (이슈 #148) migration 007 의 좁은 ArticleURLPattern 을 빈 문자열로 갱신: - naver / daum / yonhap / cnn 의 list rule 4건 UPDATE - article_url_pattern: "" → all-pass discovery - exclude_patterns: 사이트별 노이즈 컷 (광고/공유/네비/미디어/about/login 등) - same_origin_only / max_links_per_page 는 site profile 유지 운영자가 라이브 모니터링 후 ExcludePatterns 점진 추가하여 noise 정밀화. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…m sample (이슈 #148) 기존: 단순 cap (len >= maxOut 시 break) — 페이지 상단 광고/네비 영역에 편향됨 신규 정책: 1. same-origin (raw.URL host 와 동일) 링크는 maxOut 무시하고 모두 통과 2. cross-origin 은 잔여 슬롯 (maxOut - len(same)) 만큼 math/rand/v2.Shuffle 로 무작위 sample 3. maxOut == 0 (무제한) 이면 cross 도 모두 통과 이유: - 사이트 자체 컨텐츠 (same) 는 noise 적고 가치 높음 — 모두 발행 가치 - 외부 링크 (cross) 는 광고/제휴 noise 많음 — cap 으로 통제 + 무작위 sample 로 특정 영역 (예: 페이지 상단 sponsored slot) 편향 회피 테스트 재조정 (5건): - TestPageLinkDiscovery_MaxLinksPerPage_SameOriginUnlimited (same 5건은 cap=2 무시) - _CrossOriginFillsRemaining (cap 여유 있을 때 cross 채움) - _Unlimited (maxOut=0 모두 통과) - _SameOriginOnlyMode (SameOriginOnly=true 면 cross 사전 제거) - _CrossOriginRandomSample (cross 풀 > 잔여 슬롯 → random 2개 sample) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Gemini medium × 2: - internal/storage/parsing_rule.go LinkDiscoveryConfig 주석 갱신: - "빈 ArticleURLPattern → discovery 비활성화" → "all-pass 모드" - "ItemContainer fallback 은 LinkDiscovery 자체가 nil 일 때만" 명시 - MaxLinksPerPage 주석에 same-origin 우선 + cross random sample 정책 명시 (이슈 #148) - migrations/up/008 주석 갱신: - "same_origin_only: true (외부 도메인 차단)" 가 실제 SQL (yonhap만 true) 와 불일치 - "site profile 유지 (yonhap=true / naver/daum/cnn=false — 기존 설정값 보존)" 으로 정정 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Coderabbit minor × 2: - TestPageLinkDiscovery_EmptyPattern_PathPrefixesStillApply 신규 케이스 all-pass 모드에서도 PathPrefixes 가 path 기반 1차 cutoff 로 동작 확인 - TestParser_ParseLinks_LinkDiscoveryWithEmptyPattern_AllPassDiscovery 강화 기존 listHTML 은 두 경로 (discovery / ItemContainer fallback) 모두 같은 3건 반환 → discovery 가 진짜 동작하는지 증명 안 됨. ItemContainer 를 매칭 0건 selector 로 변경 — fallback 진입 시 ErrParseFailure 보장, 그래도 3건 반환되면 discovery 경로 동작의 명백한 증거. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
연관 이슈
이슈 #100 / #139 후속. 사이트별 "기사 URL" regex 강제로 인해 누락되던 비-article 컨텐츠
(공지/이벤트/시리즈/오피니언/멀티미디어 등) 를 모두 수집하도록 LinkDiscovery 의 pattern 을 optional 로 강등.
구현 내용
1. PageLinkDiscovery 컴포넌트 — pattern optional
internal/crawler/parser/rule/discovery.gocfg.ArticleURLPattern빈 문자열 시 regex compile/매칭 단계 skippkg/links.Extractor의 SameOriginOnly / PathPrefixes / ExcludePatterns / MaxLinksPerPage 만으로 필터2. rule.Parser ParseLinks 분기 완화
internal/crawler/parser/rule/parser.gocfg != nil && cfg.ArticleURLPattern != \"\"→ discoverycfg != nil→ discovery (빈 pattern 도 all-pass 모드)3. Migration 008 — 운영 사이트 rules all-pass 전환
article_url_pattern빈 문자열로 갱신exclude_patterns강화 — 사이트별 광고/공유/네비/미디어/about/login 등 노이즈 컷max_links_per_page=200,same_origin_onlysite profile 유지5. MaxLinksPerPage 우선순위 정책 (추가 commit)
사용자 피드백 반영 —
same-origin우선 +cross-originrandom sample 로 변경:maxOut무시하고 모두 통과maxOut - len(same)) 만큼math/rand/v2.Shuffle로 무작위 samplemaxOut == 0(무제한) 이면 cross 도 모두 통과이유:
4. 테스트 갱신 (3건)
TestPageLinkDiscovery_EmptyPattern_AllPass— 빈 pattern 으로 모든 same-origin 링크 통과 + 기본 제외 (login 등) 차단 검증TestPageLinkDiscovery_EmptyPattern_ExcludeStillApplies— all-pass 모드에서 ExcludePatterns 동작TestParser_ParseLinks_LinkDiscoveryWithEmptyPattern_AllPassDiscovery— 객체만 있고 pattern 비었을 때 all-pass discovery 진입 (ItemContainer fallback X)TestPageLinkDiscovery_EmptyPattern_ReturnsEmptySelector는 의미 변경에 따라 위 케이스로 대체CI / 머지 게이트 점검
변경 영향 범위
internal/crawler/parser/rule/{discovery.go, parser.go}migrations/{up,down}/008_*.sqltest/internal/parser/rule/discovery_test.goMediumRequired Status Checks
Commit LintPR Title LintLinked Issue CheckFormat CheckBuildTestLint배포 순서
chained article jobs published에서url_count증가 추이issuetracker.crawl.normal토픽 lag롤백 계획
git revert(4 commits, 역순)후속 작업 (별도 PR)
Summary by CodeRabbit
Bug Fixes
Chores