# KnowHub 重建与去重工作交接文档

**日期**：2026-04-21
**上下文**：修复同事 agent 失控污染的 tao_dev_1 数据，统一为 `howard_dedup` 版本；同时系统化去重，建立正确的需求-能力关系。

---

## 一、DB 当前状态

| 表 | 计数 | 版本分布 |
|---|---|---|
| capability | **315** | 全部 `howard_dedup` |
| strategy | **94** | 全部 `howard_dedup` |
| resource | **2508** | 全部 `howard_dedup` |
| requirement | 99 | 全部 `v0`（**未动**，不要动） |
| knowledge | 1046 | 未动 |

| junction 表 | 计数 |
|---|---|
| requirement_capability | 659 ⚠️ 不完整（见待办 2） |
| capability_tool | 1275 |
| capability_knowledge | 0（源数据无） |
| capability_resource | 0（源数据无） |
| strategy_capability | 660 |
| strategy_resource | 2585 |
| requirement_strategy | 94 |
| requirement_resource | 2585 |

### 关键 schema 提醒

| 表 | 是否有 relation_type 列 |
|---|---|
| strategy_capability | ✅ 有（值：`'compose'`） |
| capability_knowledge | ✅ 有 |
| strategy_knowledge | ✅ 有 |
| **requirement_capability** | ❌ **没有，不要加**（按 A 方案，语义 = 研究发现的所有 cap） |
| 其他 junction | 都没有（只有 FK 两列） |

---

## 二、已完成的工作

### 2.1 历次 capability 去重（ROUND 1 → 2 → C → 4）
对原 `tao_dev_1` + `v0` 数据做了 4 轮合并：
- **Round 1**：手动聚类 35 簇，合并 112 条 member + 删 22 条 VCAP（`CAP-tao_dev_1-NN-NN` 占位）→ 465 → 331
- **Round 2**：26 簇跨领域合并 → 331 → 289
- **Round C**：6 条跨版本（v0 foundation 吸收 tao_dev_1 同义条）→ 289 → 283
- **Round 4**：修复 rebuild 时 alias 漏判产生的 32 条新 dup → 354 → 315

### 2.2 数据重建（从 `/Users/sunlit/Downloads/output 2/` 99 folder）
由于同事的 agent 失控污染：
- purge 所有 capability/strategy/resource（v0 + tao_dev_1）+ 所有 junction
- seed 历次合并 canonical + 21 条 v0 foundation（+重建 CAP-006）
- 从 99 folder 重 ingest，全部标 version=`howard_dedup`
- 别名表 536 条确保**跨所有历史名字**都能命中已有 canonical，避免二次重复

### 2.3 手动修复 6 个 malformed folder
源数据 schema 不标准但有内容可抢救：
- **004**: `strategy.strategy.phases` + `capability_mapping` (cap name only)
- **031**: `strategy.strategy.phases` + `capability_mapping` (capability_id/name)
- **044**: `capabilities_extracted` 用老 schema（`capability_id`/`capability_name`）
- **053**: `phases[]` 顶层 list + `core_workflow` 文本
- **066**: `execution_phases` + `key_capabilities`
- **070**: `capabilities_mapping` only

全部已经手动解析 + DB 写入。

### 2.4 Rename & 扩写
32 条 canonical 的 name/description 被改写以覆盖合并后的语义范围（应用 `rename_merged_capabilities.py`）。

### 2.5 capability_tool 回填
从 `capabilities_extracted.json` 的 `implements` 字段反向回填了 1275 条 cap-tool 关系。

---

## 三、已创建的脚本（`knowhub/scripts/`）

| 脚本 | 作用 | 幂等 |
|---|---|---|
| `merge_capabilities.py` | 4 轮 canonical 合并映射 + junction 冲突处理 | ✅ |
| `rename_merged_capabilities.py` | 32 条 canonical 改名 | ✅ |
| `rebuild_howard_dedup.py` | 全量重建：purge → seed → ingest output 2/ → 改名 | ✅（resume mode） |
| `dedup_howard_round4.py` | Round 4 修复 rebuild 产生的 dup | ✅ |
| `salvage_malformed_folders.py` | 早期尝试处理 malformed folder 的脚本（未使用，我后来手动处理了） | - |

所有脚本使用 `autocommit=True`，每次操作独立提交——连接断了可以直接重跑。

---

## 四、备份位置

`/tmp/knowhub_backup_2026-04-21/`（执行 rebuild 前完整快照）
- `capability.json` (365 rows, 原 v0+tao_dev_1 混合状态)
- `strategy.json`、`resource.json`、`requirement.json`、`knowledge.json`
- 所有 junction 表的 JSON 快照

`/tmp/capabilities_all.md`（465 条 tao_dev_1 pre-round-1 原始快照，重建时作为别名源）

---

## 五、待完成工作（按优先级）

### 待办 1：补齐历史 requirement_capability 到"研究全集"（方案 A）

**问题**：当前 `req_cap=659` 基本等于 `strat_cap=660` 的镜像，只含 strategy 的 `workflow_outline` 子集。按 A 方案设计应该是所有 `capabilities_extracted.json` 里出现的 caps 全集（research-discovered）。

**操作**：
1. 遍历 `/Users/sunlit/Downloads/output 2/` 的 99 个 folder
2. 读 `capabilities_extracted.json`，对每个 cap 用 **alias map 解析成 howard_dedup canonical ID**（逻辑与 `rebuild_howard_dedup.py` 的 cap resolution 部分一致）
3. `INSERT INTO requirement_capability (requirement_id, capability_id) VALUES (REQ_NN, CAP-X) ON CONFLICT DO NOTHING`
4. 对 malformed 格式的 folder（044 用 `capability_id`/`capability_name`、053 用 `phases` 里的 caps 等）也要按特殊结构处理——参考 `salvage_malformed_folders.py` 的逐 folder 处理逻辑

**预期增量**：1016 cap_entries(含重复) - dedup → 约 900 个 (req, cap) pairs；现有 659 → 预期 ~900+。

**不要**：
- 不要加 `relation_type` 列
- 不要动 strategy_capability（保持 compose 语义）

### 待办 2：处理 5 份重跑数据（等用户发来）

User 将提供 032/046/069/085/097 的重跑数据（可能是新的 folder 替换）。
处理时必须：

1. **检查现有孤儿数据**：
   - `REQ_032`：DB 已有 24 条 resource（folder=032 tag），没 junction
   - `REQ_069`：25 条
   - `REQ_085`：36 条
   - `REQ_097`：24 条
   - `REQ_046`：0 条（从未入库）
   - 如果新数据含这些 URL：`INSERT ... ON CONFLICT` 会更新同样的 resource（URL hash ID 确定）
   - 如果新数据不含某些 URL：旧 resource 就是孤儿（考虑删除或保留）

2. **按 rebuild_howard_dedup.py 的 ingest_folder 逻辑处理**：
   - match requirement by exact description
   - create resources（howard_dedup version）
   - resolve capabilities via alias map
   - create strategy（howard_dedup，按 is_selected=true 选 1 条）
   - wire ALL junctions including 新的 req_cap 全集逻辑（待办 1 的延伸）

3. **关键：req_cap 要写 ALL caps in capabilities_extracted，不只是 strategy 用到的**（A 方案）

### 待办 3（可选，之前说"先不忙"）：Embedding 重算

所有 315 条 capability + 94 条 strategy 的 embedding 都是空。
当用户想启用语义搜索时，批量调用 `knowhub/embeddings.py` 的 `get_embeddings_batch` 重算：
```python
for each cap: embedding = get_embedding(f"{name} {description}")
```

### 待办 4（可选）：effects/criterion 从备份回灌

Round 1-3 合并时丢失了 member caps 的 `effects` + `criterion` 数据。
用户有备份，可从 `/tmp/knowhub_backup_2026-04-21/capability.json` 的旧数据里，对当前 howard_dedup caps 做：
- 如果当前 canonical 的 effects 是 `[]`、criterion 是 `''`：从备份找同名或同 ID 的老记录合并进来

---

## 六、已知数据问题（转告同事）

### 6.1 Pipeline 输出 schema 不统一
- 5 folder 的 `strategy.json` 各造一格（`phases`/`execution_phases`/`capabilities_mapping` 等字段名）
- 1 folder（044）的 `capabilities_extracted.json` 用了老 schema
- **建议**：Pipeline 加 schema validator

### 6.2 LLM 空输出
- 069/085：`strategies: []`（没产出策略）
- 008/034/053：`extracted_capabilities: []`（没产出能力）
- **建议**：重试或 fallback

### 6.3 JSON 文件损坏
- 032：只含 `{"ping"}` 
- 046：`strategies` 是 str
- 077：JSONDecodeError
- 097：JSONDecodeError
- **建议**：atomic write（tmp+rename）

### 6.4 LLM is_new 判定不可靠
新批次 is_new=true 的 cap 大量是已有能力的重新命名。
**建议**：pipeline 在产出 is_new=true 前先做 DB 语义查重（name 精确匹配 + embedding cos）。

### 6.5 VCAP 机制已退役但 code 还在
- `decisions.md §18` 决议 VCAP 退役，但 `ingest_research_output.py` 还在造 `CAP-tao_dev_1-NN-NN`
- **建议**：下线 VCAP 分支，is_new=true 必须 pre-resolve 或降级为错误

---

## 七、下次 session 快速重建上下文的步骤

1. **读本文档**（`knowhub/docs/2026-04-21_rebuild_handoff.md`）
2. **读历史脚本**（`knowhub/scripts/rebuild_howard_dedup.py` 是主逻辑，内含 alias 构建、canonical 选择、junction 写入的全套实现）
3. **查询 DB 现状**确认未被外部干扰：
   ```python
   python -c "
   from knowhub.knowhub_db.pg_capability_store import PostgreSQLCapabilityStore
   s=PostgreSQLCapabilityStore(); cur=s._get_cursor()
   for t in ['capability','strategy','resource']:
       cur.execute(f'SELECT version, COUNT(*) AS c FROM {t} GROUP BY version')
       for r in cur.fetchall(): print(f'{t}/{r[\"version\"]}: {r[\"c\"]}')
   "
   ```
4. **开工**：优先做 **待办 1（补齐 req_cap）** 再等 **待办 2（5 份重跑数据）**

---

## 八、写入 DB 时的通用约束（务必遵守）

1. **ID 规范**（都用短 hash，ID 里不带 version）：
   - capability: `CAP-<hash8(normalized_name)>` 或 `CAP-NNN`（v0 foundation）
   - strategy: `strategy-<hash8(req_text + "|" + strategy_name)>`
   - resource: `resource/research/<platform.lower()>/<hash12(url)>`

2. **Alias 构建传递闭包**（避免 CAP-A → CAP-B → CAP-C 这种链式问题未解析到最终 canonical）：
   ```python
   member_to_canonical = {m: final_canonical for ...}
   # 遇到循环或多层嵌套时一定要解析到 final
   ```

3. **AnalyticDB 约束**：
   - 新加列 + ON CONFLICT DO UPDATE 对 beam 表不兼容 → 都改 `DELETE + INSERT`
   - `autocommit=True` 强制（否则 idle-in-tx 会长期持锁）
   - 连接不稳定 → 脚本必须幂等、支持断点续跑

4. **junction 写入全部用 `ON CONFLICT DO NOTHING`**，避免重复 PK 错误

5. **不要修改** `requirement`、`knowledge` 表及其相关 junction
