Reduce SmartStart default categories to thirteen
| | |
| | | |
| | | - `src/Apptag/SmartCategorization/SmartCategory.swift` |
| | | - 内置智能分类定义。 |
| | | - `SmartCategoryDefaults.orderedIDs` 是 SmartStart 默认初始化标签事实源;当前默认方案为 15 个标签。 |
| | | - `SmartCategoryID.smartStartDefaultCategoryID` 负责把旧细分 catalog 分类归并到 15 个默认标签;这是新 SmartStart 写入前的归并,不做老用户旧标签自动迁移。 |
| | | - `SmartCategoryDefaults.orderedIDs` 是 SmartStart 默认初始化标签事实源;当前默认方案为 13 个标签。 |
| | | - `SmartCategoryID.smartStartDefaultCategoryID` 负责把旧细分 catalog 分类归并到 13 个默认标签;`finance` 和 `other` 返回 nil,回到未分类;这是新 SmartStart 写入前的归并,不做老用户旧标签自动迁移。 |
| | | - `src/Apptag/SmartCategorization/SmartCategorizationDraft.swift` |
| | | - 智能分类草稿、默认备注 provenance、未分配应用和 warning 模型。 |
| | | - `src/Apptag/SmartCategorization/SmartStartService.swift` |
| | |
| | | - `src/Scripts/smart_category_localization_qa.sh` |
| | | - SmartCategory/default system tag 初始化标签 29 语种本地化检查;禁止非英文语言包直接复制英文标签,保留 `PDF`、`DevOps` 等技术通用词例外。 |
| | | - `src/Scripts/smartstart_default_categories_qa.sh` |
| | | - SmartStart 默认初始化标签检查;验证 15 个默认分类、catalog 分类归并入口、首次 starter tags 和关键多语言目标文案。 |
| | | - SmartStart 默认初始化标签检查;验证 13 个默认分类、catalog 分类归并入口、`finance` / `other` 回未分类、首次 starter tags 和关键多语言目标文案。 |
| | | - `src/Scripts/quick_search_app_name_qa.sh` |
| | | - Quick Search 应用显示名回归。 |
| | | - `src/Scripts/quick_search_system_app_qa.sh` |
| | |
| | | guard let entry = entry(for: app) else { return nil } |
| | | let categoryIDs = entry.defaultTag |
| | | .compactMap { SmartCategoryID(rawValue: $0) } |
| | | .filter { $0 != .other } |
| | | .map(\.smartStartDefaultCategoryID) |
| | | .compactMap(\.smartStartDefaultCategoryID) |
| | | guard !categoryIDs.isEmpty else { return nil } |
| | | return AppleDefaultCategorization( |
| | | canonicalName: entry.canonicalName, |
| | |
| | | <key>CFBundlePackageType</key> |
| | | <string>APPL</string> |
| | | <key>CFBundleShortVersionString</key> |
| | | <string>8.1.3</string> |
| | | <string>8.1.4</string> |
| | | <key>CFBundleVersion</key> |
| | | <string>20260627.1605</string> |
| | | <string>20260627.1643</string> |
| | | <key>LSApplicationCategoryType</key> |
| | | <string>public.app-category.utilities</string> |
| | | <key>LSMinimumSystemVersion</key> |
| | |
| | | } |
| | | } |
| | | |
| | | var smartStartDefaultCategoryID: SmartCategoryID { |
| | | var smartStartDefaultCategoryID: SmartCategoryID? { |
| | | switch self { |
| | | case .pdf, .productivity, .writing: |
| | | return .office |
| | |
| | | return .design |
| | | case .media, .video, .audio, .game: |
| | | return .entertainment |
| | | case .finance, .other: |
| | | return nil |
| | | default: |
| | | return self |
| | | } |
| | |
| | | .design, |
| | | .picturePhoto, |
| | | .entertainment, |
| | | .finance, |
| | | .education, |
| | | .other |
| | | .education |
| | | ] |
| | | |
| | | static let definitions: [SmartCategoryDefinition] = orderedIDs.map { |
| | |
| | | let entries = base.entries.compactMap { entry -> SmartStartCatalogEntry? in |
| | | let tagIDs = entry.defaultTag |
| | | .compactMap { SmartCategoryID(rawValue: $0) } |
| | | .filter { $0 != .other } |
| | | .map(\.smartStartDefaultCategoryID) |
| | | .compactMap(\.smartStartDefaultCategoryID) |
| | | guard !tagIDs.isEmpty else { return nil } |
| | | |
| | | return SmartStartCatalogEntry( |
| | |
| | | |
| | | ## [Unreleased] |
| | | |
| | | ## [8.1.4] — 2026-06-27 |
| | | |
| | | - 继续精简 SmartStart 智能初始化默认分类:新用户 / 重置智能初始化方案后的默认标签从 15 个收敛为 13 个 |
| | | - `Finance / 财务` 和 `Other / 其他` 不再作为默认智能初始化标签;catalog 中命中这两类的应用会回到未分类,不会被强行归入其它标签 |
| | | - 保持不做老用户迁移:已有用户的旧标签和手动分类关系不扫描、不改名、不删除 |
| | | - 更新 `Scripts/smartstart_default_categories_qa.sh`,防止 `finance` / `other` 重新进入默认标签或 catalog 归一化结果 |
| | | - 版本号更新为 `8.1.4`,Build 更新为 `20260627.1643` |
| | | |
| | | ## [8.1.3] — 2026-06-27 |
| | | |
| | | - 精简 SmartStart 智能初始化默认分类:新用户 / 重置智能初始化方案后的默认标签从 39 个收敛为 15 个,降低初次使用时的分类冗余 |
| | |
| | | |
| | | 日期:2026-06-27 |
| | | |
| | | 状态:产品已确认 `network-tools` 归入 `System Tools / 系统工具`;确认 `system-tools` 的用户可见名称采用 `System Tools / 系统工具`;确认 `office`、`PDF`、`writing` 合并为 `Office & Docs / 办公文档`;确认 `Video / Audio / Games` 合并进 `Entertainment / 影音娱乐`,最终默认智能分类为 15 个。 |
| | | 状态:产品已确认 `network-tools` 归入 `System Tools / 系统工具`;确认 `system-tools` 的用户可见名称采用 `System Tools / 系统工具`;确认 `office`、`PDF`、`writing` 合并为 `Office & Docs / 办公文档`;确认 `Video / Audio / Games` 合并进 `Entertainment / 影音娱乐`;确认 `Finance / 财务` 和 `Other / 其他` 回到未分类,最终默认智能分类为 13 个。 |
| | | |
| | | ## 1. 本轮目标 |
| | | |
| | | 用户反馈当前智能初始化使用 39 个默认标签,过于冗余。本方案把默认标签精简为 15 个,并明确合并关系、最终标签列表与后续落地注意事项。 |
| | | 用户反馈当前智能初始化使用 39 个默认标签,过于冗余。本方案把默认标签精简为 13 个,并明确合并关系、最终标签列表与后续落地注意事项。 |
| | | |
| | | ## 2. 当前 39 个初始化标签 |
| | | |
| | |
| | | - 合并后能进一步降低默认标签数量,避免新用户第一屏出现过多细分分类。 |
| | | - `Entertainment / 影音娱乐`作为总标签更适合默认初始化;如果用户需要细分,可后续手动拆分。 |
| | | |
| | | ### 改动 6:Finance / Other 回到未分类 |
| | | |
| | | `Finance / 财务` 和 `Other / 其他` 不再作为默认智能初始化标签。 |
| | | |
| | | 确认理由: |
| | | |
| | | - 财务类 App 对普通用户并非高频默认分类,默认展示会增加标签冗余。 |
| | | - `Other / 其他` 本质上不是智能分类结果,而是“无法确定分类”的兜底状态,应该回到未分类。 |
| | | - 本轮仍不做老用户迁移;已有用户手动创建或历史保留的财务 / 其他标签不自动删除、不改名、不迁移。 |
| | | |
| | | ## 4. 命名确认 |
| | | |
| | | ### System Tools |
| | |
| | | |
| | | 当前:39 个默认标签。 |
| | | |
| | | 合并后:15 个默认标签。 |
| | | 合并后:13 个默认标签。 |
| | | |
| | | 减少:24 个标签。 |
| | | 减少:26 个标签。 |
| | | |
| | | ## 6. 最终 15 个默认标签列表 |
| | | ## 6. 最终 13 个默认标签列表 |
| | | |
| | | 以下列表按“尽量保留原始顺序 + 合并项放在首次出现位置”的原则排列。 |
| | | |
| | |
| | | | 10 | `design` | Design | 设计 | 原 17、18、19、20 | |
| | | | 11 | `picture-photo` | Photos | 图片 | 原 25 | |
| | | | 12 | `entertainment` | Entertainment | 影音娱乐 | 原 22、23、24、34、35 | |
| | | | 13 | `finance` | Finance | 财务 | 原 36 | |
| | | | 14 | `education` | Education | 学习 | 原 37 | |
| | | | 15 | `other` | Other | 其他 | 原 39 | |
| | | | 13 | `education` | Education | 学习 | 原 37 | |
| | | |
| | | ## 7. 完整合并映射表 |
| | | |
| | |
| | | | 33 | `network-tools` | 网络工具 | `system-enhancement` | 系统工具 | |
| | | | 34 | `entertainment` | 影音娱乐 | `entertainment` | 影音娱乐 | |
| | | | 35 | `game` | 游戏 | `entertainment` | 影音娱乐 | |
| | | | 36 | `finance` | 财务 | `finance` | 财务 | |
| | | | 36 | `finance` | 财务 | 未分类 | 不创建默认标签 | |
| | | | 37 | `education` | 学习 | `education` | 学习 | |
| | | | 38 | `security` | 安全 | `system-enhancement` | 系统工具 | |
| | | | 39 | `other` | 其他 | `other` | 其他 | |
| | | | 39 | `other` | 其他 | 未分类 | 不创建默认标签 | |
| | | |
| | | ## 8. 后续落地建议 |
| | | |
| | | 如果产品确认这版列表,建议后续实现按低风险路径做: |
| | | |
| | | 1. 调整 `SmartCategoryDefaults.orderedIDs`,把 39 个默认标签压缩为 15 个。 |
| | | 1. 调整 `SmartCategoryDefaults.orderedIDs`,把 39 个默认标签压缩为 13 个。 |
| | | 2. 复用既有 `SmartCategoryID.office`、`SmartCategoryID.development`、`SmartCategoryID.design`、`SmartCategoryID.systemEnhancement` 作为合并目标。 |
| | | 3. 建立旧 category id 到新 category id 的映射表,SmartStart 匹配结果统一归并后再写入标签。 |
| | | 4. 29 个语言包中将 `system-enhancement` 的用户可见文案改为 `System Tools / 系统工具`对应语义,将 `office` 改为 `Office & Docs / 办公文档`对应语义,将 `picture-photo` 简化为 `Photos / 图片`对应语义。 |
| | | 5. QA 覆盖: |
| | | - 新用户智能初始化最终标签数是 15。 |
| | | - 新用户智能初始化最终标签数是 13。 |
| | | - 合并来源 app 进入正确目标标签。 |
| | | - 第 33 项 `network-tools`归入 `system-enhancement`,不重复创建标签。 |
| | | - `office`、`PDF`、`writing`都归入 `Office & Docs / 办公文档`。 |
| | | - `finance` 和 `other` 不生成默认标签,命中后回到未分类。 |
| | | - 新默认智能分类结果中 29 语种没有旧细分标签残留、没有英文兜底污染。 |
| | | - 老用户已有标签保持原样;本轮不做旧 39 标签自动迁移。 |
| | | |
| | |
| | | "design", |
| | | "picturePhoto", |
| | | "entertainment", |
| | | "finance", |
| | | "education", |
| | | "other", |
| | | ] |
| | | |
| | | EXPECTED_RAW_IDS = { |
| | |
| | | "design", |
| | | "picture-photo", |
| | | "entertainment", |
| | | "finance", |
| | | "education", |
| | | "other", |
| | | } |
| | | |
| | | DROP_RAW_IDS = {"finance", "other"} |
| | | |
| | | MERGE_MAP = { |
| | | "PDF": "office", |
| | |
| | | "case .font, .uiPrototyping, .threeDCAD, .diagramming:", |
| | | "case .media, .video, .audio, .game:", |
| | | "return .entertainment", |
| | | "case .finance, .other:", |
| | | "return nil", |
| | | ] |
| | | missing_snippets = [snippet for snippet in required_mapping_snippets if snippet not in swift] |
| | | if missing_snippets: |
| | |
| | | |
| | | for path in [smartstart, apple_catalog]: |
| | | text = path.read_text(encoding="utf-8") |
| | | if ".map(\\.smartStartDefaultCategoryID)" not in text: |
| | | if ".compactMap(\\.smartStartDefaultCategoryID)" not in text: |
| | | fail(f"{path.name} must normalize catalog category IDs through smartStartDefaultCategoryID") |
| | | |
| | | starter_match = re.search( |
| | |
| | | if legacy_starter_cases: |
| | | fail("starterCategoryIDs contains non-default categories: " + ", ".join(sorted(legacy_starter_cases))) |
| | | |
| | | def normalize(raw: str) -> str: |
| | | def normalize(raw): |
| | | if raw in DROP_RAW_IDS: |
| | | return None |
| | | return MERGE_MAP.get(raw, raw) |
| | | |
| | | for catalog_path in [smartstart_base, apple_base]: |
| | |
| | | unexpected = {} |
| | | for entry in catalog.get("entries", []): |
| | | for raw in entry.get("defaultTag", []): |
| | | if raw == "other": |
| | | continue |
| | | normalized = normalize(raw) |
| | | if normalized is None: |
| | | continue |
| | | if normalized not in EXPECTED_RAW_IDS: |
| | | unexpected.setdefault(raw, normalized) |
| | | if unexpected: |
| | |
| | | print( |
| | | "PASS SmartStart default categories: " |
| | | f"{len(EXPECTED_ORDERED_CASES)} defaults, catalog IDs normalized, " |
| | | "starter tags restricted, target labels checked" |
| | | "finance/other uncategorized, starter tags restricted, target labels checked" |
| | | ) |
| | | PY |