# Catalog Governance

目录治理决定两件事：什么样的记录可以进入统一目录，以及进入后这些字段能表达什么、不能表达什么。

## 治理目标

这个仓库维护的是目录，不是镜像站，也不是第三方资源托管平台。治理目标因此也有限定：

- 统一记录结构
- 提高可搜索性和可安装性
- 给出可解释的排序、健康度和风险信号
- 保留人工纠偏入口

治理目标不包括：

- 对第三方资源做安全担保
- 对第三方资源做长期可用性担保
- 把所有上游差异消灭成同一种事实模型

## 记录模型

当前 schema 的核心字段包括：

- `id`
- `name`
- `type`
- `description`
- `source_url`
- `stars`
- `category`
- `tags`
- `tech_stack`
- `install`
- `source`
- `last_synced`

其中 `mcp` 和 `skill` 还要求 `added_at`。

这些字段里，最容易被误解的是下面几类：

| 字段 | 作用 | 不能推导出的结论 |
| --- | --- | --- |
| `id` | 仓库内部稳定标识 | 上游平台的原生主键 |
| `source_url` | 主要来源链接、去重和追溯依据 | 资源的唯一世界身份 |
| `category` | 目录里的主视角分类 | 资源的完整语义归属 |
| `tags` / `tech_stack` | 检索和推荐辅助信号 | 严格、完备的技术本体 |
| `install` | 当前建议的接入方式 | 所有环境一定成功的安装承诺 |
| `source` | 条目来源 | 条目质量等级 |

## 类型边界

当前目录只有四种类型：

- `mcp`
- `skill`
- `rule`
- `prompt`

四类资源共享同一套目录结构，但字段语义并不完全对称。

最直接的例子：

- `stars` 在 `mcp` 和 `skill` 上通常更有参考价值。
- `rule` 和 `prompt` 常常来自大仓库切片，`stars` 为 `null` 并不等于“0 star”。
- `install` 对 `mcp` 和 `skill` 更关键，对 `prompt` 的约束通常更弱。

因此，目录支持统一查询，不代表所有字段都能跨类型等值比较。

## 自动同步与 curated

目录输入来自两类来源：

- 自动同步产物：`catalog/<type>/index.json`
- 人工补充入口：`catalog/<type>/curated.json`

这两者的分工不同。

### 自动同步产物

适合承载：

- 覆盖面
- 更新频率
- 低成本批量采集

不适合承载：

- 高精度人工判断
- 复杂语义修正
- 长期手工维护承诺

### curated

适合承载：

- 高价值条目的精修
- 自动流程拿不到的补充信息
- 人工确认后的标签、技术栈、安装说明

不适合承载：

- 对全局规则的替代
- 对自动同步机制的兜底
- “想怎么盖就怎么盖”的手工覆盖层

### 当前主干的实际规则

当前 `scripts/merge_index.py` 的 `overlay_curated_fields()` 明确把 curated 定义为补充层，而不是事实重写层：

- `tags` 会补充
- `tech_stack` 会补充
- 找不到匹配项时可以追加为新条目
- `name`、`description`、`stars`、`source_url`、`install`、`evaluation` 不会在这里被无条件覆盖

所以 curated 的边界不是“优先级最高”，而是“人工补充优先”。

## 去重

当前主干的关键去重依据是：

- `id`
- 标准化后的 `source_url`

这套规则能解决：

- 同一资源被重复收录
- 不同上游指向同一来源
- 人工补充和自动同步之间的落点对齐

这套规则不能解决：

- 同一仓库内多个资源的精细拆分
- 一个仓库多种安装形态是否应该视为不同消费对象
- 上游链接本身错误、歧义或跳转异常

去重的目标是减少重复，不是建立绝对唯一真相。

## 分类

`category` 使用受控枚举，不是自由文本。

这样做的好处是：

- 搜索和筛选更稳定
- 非法值更容易暴露

限制也同样明确：

- 多领域资源一定会损失部分语义
- 某些资源天然难以只归到一个类

因此 `category` 更接近“目录主分类”，不是完整分类学。

## 评分与健康度

目录里的治理信号主要分两组：

- `evaluation.*`
- `health.*`

### `evaluation.*`

这是排序和治理用信号。当前 `scripts/scoring_governor.py` 会按类型使用不同权重和阈值，生成 `final_score`，再推导 `accept` / `review` / `reject`。

它代表：

- 目录如何看待这条记录
- 排序和过滤时该给它多大权重

它不代表：

- 资源的绝对质量结论
- 人工评审可以被完全替代

### `health.*`

这是维护和风险提示用信号。它适合表达：

- 资源最近是否活跃
- 安装和质量是否大致可信
- 某条资源是否应该在结果里降权

它不适合表达：

- 项目已经“死亡”
- 资源应该直接删除

长期稳定但不常更新的项目，和真正弃坑的项目，在现实里并不总能靠一个阈值分清。

## `install` 字段

`install` 的价值很高，因为这个仓库不仅负责发现资源，还试图让资源能够接入。

但 `install` 的语义必须收窄理解：

- 它表示当前仓库建议的接入方式。
- 它不表示所有环境一定成功。
- 它不表示第三方未来不会改安装方法。
- 它不表示本仓库对第三方安装脚本承担持续维护责任。

把 `install` 看成结构化操作建议是对的，把它看成运行保证是不对的。

## 校验

`scripts/validate_curated.py` 负责 curated 入口的基础约束检查。

它当前能覆盖的范围包括：

- 必填字段
- 类型枚举
- 安装方式枚举
- `id` 格式
- 一部分重复提醒

它不覆盖：

- 描述是否足够好
- 条目是否真的值得收录
- 合并后的最终排序是否符合预期
- 语义层面的错误修复

校验通过只说明“格式基本成立”，不说明“目录质量已经足够好”。

## 仓库到底担保到哪

仓库担保的是：

- 目录结构尽量统一
- 信号尽量可解释
- 分发入口尽量稳定

仓库不担保的是：

- 第三方资源永远可用
- 第三方资源没有安全风险
- 第三方资源未来不改路径、不删仓库、不改协议

目录型仓库一旦把担保边界写模糊，后面就会被期待成平台责任全包。
