Skip to content

feat: 按实际生效标签归类分类 + 保留手动分类归属 - #264

Merged
AmintaCCCP merged 6 commits into
mainfrom
feat/effective-category-matching-262
Aug 8, 2026
Merged

feat: 按实际生效标签归类分类 + 保留手动分类归属#264
AmintaCCCP merged 6 commits into
mainfrom
feat/effective-category-matching-262

Conversation

@AmintaCCCP

@AmintaCCCP AmintaCCCP commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Closes #262

背景

matchesCategory() 分类匹配只读取 ai_tags,导致分类归属与卡片实际展示的标签不一致:

  • 用户手动编辑的 custom_tags 不参与分类匹配
  • 自定义分类在 AI 分析后会被内置分类匹配结果静默清除(resolveCategoryAssignment 返回 undefined
  • 无关键词的自定义分类在无 Topics 的仓库上很难被命中

变更

1. 新增 categoryMatchMode 设置(默认 effective

  • effective(推荐,默认):按卡片展示的标签归类 custom_tags > ai_tags > topics
  • legacy:保留旧版仅按 ai_tags 归类
  • 设置面板「仓库归类方式」单选,含解释文案

2. matchesCategory 支持模式参数

  • 新增 getEffectiveTags()tagMatchesCategory() 辅助函数
  • effective 模式下自定义分类额外支持分类名互相包含匹配(解决无关键词自定义分类无法命中)

3. resolveCategoryAssignment 保留手动归属

  • 已有的有效 custom_category(含显式清空)不再被 AI 分析覆盖
  • 自定义分类名称按互相包含匹配,内置分类保持精确匹配

4. 自定义分类 metadata 兜底归类(新)

  • 新增 getRepoText() 聚合仓库元数据(名称 / 描述 / 语言 / topics / AI 摘要)
  • 新增 buildCategoryHints():生成自定义分类「名称 + 关键词」提示,注入 AI 分析提示词(中英文默认提示与 {CATEGORIES_HINT} 占位符),让模型在仓库无 Topics 时也能识别自定义分类
  • resolveCategoryAssignment 在 AI 标签为空或未命中自定义分类时,按仓库元数据关键词兜底匹配自定义分类(空关键词分类回退到分类名包含匹配)
  • aiAnalysisHelper / aiAnalysisOptimizer(单仓、批量、Discovery 流水线)均透传 hints;提示词注入处统一经 sanitizeForPrompt 消毒

5. 调用方

  • 仓库列表过滤、侧边栏分类计数均读取配置的匹配模式

测试

  • categoryUtils.test.ts 扩展到 26 个用例(有效标签优先级、自定义分类名匹配、归属保留、metadata 兜底、建 hints 等)
  • vitest run 187 个全部通过;tsc --noEmit 通过;本次改动文件 eslint 通过

Summary by CodeRabbit

  • New Features
    • Added category matching settings with Effective and Legacy modes.
    • Effective matching prioritizes custom tags, AI tags, and topics, and supports custom category names.
    • Category counts and repository filtering now reflect the selected matching mode.
    • AI analysis now uses custom category hints for more relevant classification.
    • Custom tags are now included in repository search.
    • User-defined category assignments and explicit clears are preserved.
  • Bug Fixes
    • Improved category assignment and persisted settings handling.
    • Invalid or missing matching-mode settings now default to Effective mode.

…tegories

Implements issue #262 by introducing a new 'effective' category matching
mode (default) that ranks repositories using the same tags shown on cards
(custom_tags > ai_tags > topics) instead of only ai_tags.

- add getEffectiveTags() and a mode-aware matchesCategory()
- persist categoryMatchMode (default 'effective') with a settings radio
- resolveCategoryAssignment: preserve manually assigned/cleared custom
  categories from being overwritten by AI analysis; match custom category
  names by mutual substring
- sidebars and category counts now honor the configured match mode
@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR adds persisted legacy and effective matching modes. It updates category assignment, filtering, counts, and AI analysis. Custom category hints now reach localized analysis prompts and repository search.

Changes

Category matching and analysis

Layer / File(s) Summary
Matching mode contract and persistence
src/types/index.ts, src/store/useAppStore.ts
The store defines categoryMatchMode, defaults to effective, validates hydrated values, and persists updates.
Matching and assignment rules
src/utils/categoryUtils.ts, src/utils/categoryUtils.test.ts
Category utilities select effective tags, support both modes, infer custom categories from repository metadata, preserve explicit assignments, and test matching precedence.
Settings and repository views
src/components/settings/CategoryPanel.tsx, src/components/CategorySidebar.tsx, src/components/RepositoryList.tsx
The settings panel updates the selected mode. Category counts and repository filtering use that mode.
Category hints in AI analysis
src/components/DiscoveryView.tsx, src/components/RepositoryList.tsx, src/services/aiAnalysisHelper.ts, src/services/aiAnalysisOptimizer.ts, src/services/aiService.ts, src/services/aiService.test.ts
Custom category names and keywords flow into standard, bulk, and localized AI analysis prompts. Repository searches also match custom_tags.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CategoryPanel
  participant useAppStore
  participant RepositoryList
  participant AIAnalysisOptimizer
  participant AIService
  CategoryPanel->>useAppStore: setCategoryMatchMode(mode)
  useAppStore-->>RepositoryList: categoryMatchMode
  RepositoryList->>AIAnalysisOptimizer: analyzeRepositoriesPipelined(categoryHints)
  AIAnalysisOptimizer->>AIService: analyzeRepository(categoryHints)
  AIService-->>RepositoryList: categorized repository analysis
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确概括了按实际生效标签分类和保留手动分类归属这两个主要变更。
Linked Issues check ✅ Passed 实现覆盖了有效标签优先级、legacy 模式、手动分类保留和自定义标签影响分类等 Issue #262 的编码目标。
Out of Scope Changes check ✅ Passed 代码变更均服务于 Issue #262,包括分类匹配、设置持久化、AI 提示传递、搜索一致性和相关测试。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/effective-category-matching-262

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/settings/CategoryPanel.tsx`:
- Around line 335-339: Update the descriptive copy near the mode-specific
category text in CategoryPanel so protection of manually assigned
custom_category values is stated independently of matching mode. Remove it from
effective-only wording or place it in shared mode-neutral copy, while preserving
the existing tag-source explanation.
🪄 Autofix

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 Plus

Run ID: 1792ce6a-a6dc-4eed-b6b5-4be344131386

📥 Commits

Reviewing files that changed from the base of the PR and between 10654e3 and 5708757.

📒 Files selected for processing (7)
  • src/components/CategorySidebar.tsx
  • src/components/RepositoryList.tsx
  • src/components/settings/CategoryPanel.tsx
  • src/store/useAppStore.ts
  • src/types/index.ts
  • src/utils/categoryUtils.test.ts
  • src/utils/categoryUtils.ts

Comment thread src/components/settings/CategoryPanel.tsx
Per CodeRabbit review: the resolveCategoryAssignment preservation applies
regardless of matching mode, so the claim that manual assignments survive
AI analysis should not be stated only under the effective-mode option.
@AmintaCCCP

Copy link
Copy Markdown
Owner Author

Fixed per CodeRabbit review (commit adcf74f): moved the 'manually assigned categories are always kept' statement from the effective-mode description to the shared mode-neutral intro copy, since resolveCategoryAssignment preserves manual assignments in both modes.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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)
src/utils/categoryUtils.ts (1)

138-140: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Use the effective-tag contract in search paths.

Effective mode can classify a repository from custom_tags. AIService.performEnhancedSearch, performBasicSearch, and the static fallback do not search custom_tags. performEnhancedBasicSearch searches both tag sets without the priority rule.

The same custom tag can therefore place a repository in a category but fail to find it in search. Route all search builders through getEffectiveTags().

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/categoryUtils.ts` around lines 138 - 140, The search builders
performEnhancedSearch, performBasicSearch, performEnhancedBasicSearch, and the
static fallback must use getEffectiveTags() whenever effective mode is active.
Replace their direct or combined AI/custom tag collection with the helper’s
result so searches follow the same priority contract as category matching, while
preserving non-effective tag behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/utils/categoryUtils.ts`:
- Around line 229-232: Update the resolveCategoryAssignment calls in
RepositoryList, DiscoveryView, and aiAnalysisHelper to pass a repository copy
with ai_summary set to the current result.summary before metadata fallback runs.
Preserve existing repository fields and add a test covering a custom category
matched only by the newly generated summary.
- Around line 197-200: Update the custom-category matching logic in the category
utility to normalize keywords and exclude blank results before calling
repoText.includes, preventing whitespace-only keywords from matching every
repository. Preserve the existing category-name fallback for categories with no
valid keywords, and add a regression test covering keywords: [' '].

---

Outside diff comments:
In `@src/utils/categoryUtils.ts`:
- Around line 138-140: The search builders performEnhancedSearch,
performBasicSearch, performEnhancedBasicSearch, and the static fallback must use
getEffectiveTags() whenever effective mode is active. Replace their direct or
combined AI/custom tag collection with the helper’s result so searches follow
the same priority contract as category matching, while preserving non-effective
tag behavior.
🪄 Autofix

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 Plus

Run ID: c4dffb02-5cf2-4243-acce-26cfafdedf0a

📥 Commits

Reviewing files that changed from the base of the PR and between adcf74f and 2aae2d7.

📒 Files selected for processing (7)
  • src/components/DiscoveryView.tsx
  • src/components/RepositoryList.tsx
  • src/services/aiAnalysisHelper.ts
  • src/services/aiAnalysisOptimizer.ts
  • src/services/aiService.ts
  • src/utils/categoryUtils.test.ts
  • src/utils/categoryUtils.ts

Comment thread src/utils/categoryUtils.ts Outdated
Comment thread src/utils/categoryUtils.ts
@AmintaCCCP

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/utils/categoryUtils.test.ts`:
- Around line 409-417: Update the test around buildCategoryHints to assert the
exact normalized hint string, rather than only checking that it contains Skill
and excludes partial patterns. Verify whitespace-only keywords are removed and
the resulting hint matches the expected value, so outputs retaining those
keywords fail.
🪄 Autofix

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 Plus

Run ID: 4ae3e1f1-c6d2-4b9a-a33a-86a5414bccba

📥 Commits

Reviewing files that changed from the base of the PR and between 2aae2d7 and 6c26771.

📒 Files selected for processing (7)
  • src/components/DiscoveryView.tsx
  • src/components/RepositoryList.tsx
  • src/services/aiAnalysisHelper.ts
  • src/services/aiService.test.ts
  • src/services/aiService.ts
  • src/utils/categoryUtils.test.ts
  • src/utils/categoryUtils.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/components/DiscoveryView.tsx
  • src/services/aiService.ts
  • src/components/RepositoryList.tsx
  • src/utils/categoryUtils.ts

Comment thread src/utils/categoryUtils.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/services/aiService.test.ts (1)

86-114: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover the enhanced search path.

The tests cover static fallback search and basic search. The changed performEnhancedSearch path at Line [1451] is not exercised. Add one custom-tag-only query test for that path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/services/aiService.test.ts` around lines 86 - 114, Add a test in the
AIService search tests that exercises the performEnhancedSearch method with a
repository matching only through custom_tags and a custom-tag-only query. Assert
that the matching repository is returned, following the existing static fallback
and performBasicSearch test patterns.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/DiscoveryView.tsx`:
- Around line 813-817: Update the Discovery analysis call to
resolveCategoryAssignment so it receives the complete active category list,
including built-in and custom categories, rather than only
allCategoriesForResolution derived from storeState.customCategories. Preserve
manually assigned built-in categories and keep the existing result update flow
unchanged.

In `@src/services/aiService.ts`:
- Around line 847-851: Update the custom prompt construction around customPrompt
and the {CATEGORIES_HINT} replacement so supplied categoryHints are preserved
even when the placeholder is absent. Keep placeholder replacement working when
present, and append or otherwise merge the sanitized hints only for prompts that
do not include {CATEGORIES_HINT}.

In `@src/utils/categoryUtils.ts`:
- Around line 8-15: Update getEffectiveTags to remove blank or whitespace-only
tags from custom_tags, ai_tags, and topics before selecting the first non-empty
source, preserving fallback to the next source when filtering leaves no tags.
Also update legacy-mode tag matching to ignore blank tags before
keyword.includes or category-name containment checks, and add regression tests
covering empty custom_tags and empty ai_tags.

---

Nitpick comments:
In `@src/services/aiService.test.ts`:
- Around line 86-114: Add a test in the AIService search tests that exercises
the performEnhancedSearch method with a repository matching only through
custom_tags and a custom-tag-only query. Assert that the matching repository is
returned, following the existing static fallback and performBasicSearch test
patterns.
🪄 Autofix

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 Plus

Run ID: b36df1fd-96d3-42d4-971a-291b86568eb9

📥 Commits

Reviewing files that changed from the base of the PR and between 10654e3 and 6c26771.

📒 Files selected for processing (12)
  • src/components/CategorySidebar.tsx
  • src/components/DiscoveryView.tsx
  • src/components/RepositoryList.tsx
  • src/components/settings/CategoryPanel.tsx
  • src/services/aiAnalysisHelper.ts
  • src/services/aiAnalysisOptimizer.ts
  • src/services/aiService.test.ts
  • src/services/aiService.ts
  • src/store/useAppStore.ts
  • src/types/index.ts
  • src/utils/categoryUtils.test.ts
  • src/utils/categoryUtils.ts

Comment thread src/components/DiscoveryView.tsx
Comment thread src/services/aiService.ts Outdated
Comment thread src/utils/categoryUtils.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/utils/categoryUtils.ts (1)

238-240: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

不要把 AI 自动生成的分类当作手动归属永久保留。

DiscoveryView 会在分析成功后把 resolvedCategory 写回 custom_category,即使 category_lockedfalse。此处随后对任意有效的 repository.custom_category 直接返回。因此下一次分析不会检查新的 aiTags,而 matchesCategory 也会在 Line 147-151 提前短路。

重新分析或编辑 custom_tags 后,分类可能仍停留在旧的 AI 分类。请使用明确的来源标记区分手动归属和 AI 归属,仅保留手动值,并增加两次分析及修改标签后的回归测试。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/categoryUtils.ts` around lines 238 - 240, 更新 categoryUtils 中基于
repository.custom_category 的保留逻辑,使用明确的来源标记区分手动分类与 DiscoveryView 写入的 AI
分类;仅在分类确实由用户手动设置(包括显式清空)时直接返回,否则重新依据 aiTags 计算。同步调整相关写入流程以维护该来源标记,并为重复分析及修改
custom_tags 后重新分类增加回归测试。
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/utils/categoryUtils.ts`:
- Around line 238-240: 更新 categoryUtils 中基于 repository.custom_category
的保留逻辑,使用明确的来源标记区分手动分类与 DiscoveryView 写入的 AI 分类;仅在分类确实由用户手动设置(包括显式清空)时直接返回,否则重新依据
aiTags 计算。同步调整相关写入流程以维护该来源标记,并为重复分析及修改 custom_tags 后重新分类增加回归测试。

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 86d1bccf-b58d-4614-9d18-33a11228a9bb

📥 Commits

Reviewing files that changed from the base of the PR and between 6c26771 and 0094a12.

📒 Files selected for processing (5)
  • src/components/DiscoveryView.tsx
  • src/services/aiService.test.ts
  • src/services/aiService.ts
  • src/utils/categoryUtils.test.ts
  • src/utils/categoryUtils.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/services/aiService.test.ts
  • src/components/DiscoveryView.tsx
  • src/utils/categoryUtils.test.ts
  • src/services/aiService.ts

…tegory

Only a locked custom_category (manual) or explicit empty (cleared) is
honored in category matching/assignment. Unlocked custom_category is an
AI-analysis artifact, so it now falls through to tag/metadata matching
and is recomputed on re-analysis instead of freezing the last result.
@AmintaCCCP
AmintaCCCP merged commit 77c5112 into main Aug 8, 2026
5 checks passed
@AmintaCCCP
AmintaCCCP deleted the feat/effective-category-matching-262 branch August 8, 2026 10:31
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.

建议:matchesCategory 使用「实际生效的标签」而非仅 ai_tags

1 participant