# 归档批清与 tombstone（purge 细则 SSOT）

> 命令入口：[`/kb-archive-purge`](../../../commands/kb-archive-purge.md)。本文件为 **purge / tombstone / 查重占坑** 细则唯一出处。

## 1. 路径

| 项 | 路径 |
|----|------|
| 归档根 | `{changeDirs.archived}`（默认 `knowledge/变更/归档`） |
| tombstone | `{changeDirs.archived}/.tombstones/<change_id>.json` |
| 审计日志 | `{changeDirs.archived}/.tombstones/_audit.jsonl`（JSON Lines，追加） |

`<change_id>` 为目录名前缀的 **14 位** `YYYYMMDDHHMMSS`（与变更目录 basename 前缀一致）。`.tombstones/` 本身不是变更目录，批清扫描时跳过。

## 2. Tombstone 字段

硬删前写入（已存在同 `change_id` 的 tombstone 时**跳过、不覆盖**）：

| 字段 | 类型 | 说明 |
|------|------|------|
| `change_id` | string | 14 位时间前缀 |
| `name` | string | 中文变更名（查重按此字段匹配） |
| `dirname` | string | 原目录 basename：`<change_id>-<name>` |
| `stage` | string | 删除前 manifest stage：`archived` 或 `archived_with_debt` |
| `summary` | string | 自 `05-summary.md` 取前约 500 字或首段；无文件则为 `""` |
| `purged_at` | string | 批清时刻（ISO8601） |
| `retention_days` | number | 本次使用的 retention 天数 |
| `archived_at` | string \| null | 原 manifest `archived_at`；无则 `null` |

`_audit.jsonl` 每行一条 JSON：含上述字段，并记录相对路径等审计上下文（如 tombstone 相对路径）。

## 3. Retention 配置

业务仓 `kb.project.json`：

```json
"archivePurge": {
  "retentionDays": 90
}
```

- 缺省 **90**（插件 `DEFAULT_KB_PROJECT` / bootstrap 示例一致）。
- **仅策略批清**：脚本**无**「按单 id 删除」CLI；只按 retention 过滤过期项。
- 年龄判定优先序：`manifest.archived_at`（可解析）→ 目录名前缀 14 位按 Asia/Shanghai → 目录 mtime；未满龄跳过。

## 4. 门禁与 dry-run / confirm

1. **只扫** `changeDirs.archived` 一级子目录；跳过 `.tombstones` 与非 `^\d{14}-` 名。
2. **禁止**触碰 `changeDirs.active`（进行中）。
3. `stage` 仅 `archived` / `archived_with_debt`；否则跳过并警告。
4. 默认 **dry-run**（未传 `--confirm`）；`--confirm` 才硬删（与 `--dry-run` 同传时以 `--confirm` 为准）。
5. 执行顺序：写 tombstone → 追加 `_audit.jsonl` → `rm` 变更目录。

脚本调用：

```bash
node "${PI_KB_ROOT}/scripts/kb-archive-purge.mjs" --target "$(pwd)" --dry-run
node "${PI_KB_ROOT}/scripts/kb-archive-purge.mjs" --target "$(pwd)" --confirm --scan-wikilinks
```

## 5. 查重（propose / lite 创建前必做）

创建变更目录前，除扫描 `进行中/`、`归档/` 实体目录外，**必须**扫描 `{archived}/.tombstones/*.json` 的 **`name`** 字段。

| 命中 | 行为 |
|------|------|
| 进行中或归档下已有同名目录 | 复用该实体路径，走 `/kb-revise` 等；**不新建**第二前缀 |
| **仅** tombstone 同名命中 | **不得**把 `KB_DIR` 设成已不存在的归档路径；**不得**假装复用已删目录；**禁止**静默 `mkdir` 同名议题 |
| 推荐 | **停止并报告** tombstone（`change_id`、`dirname`、`purged_at`、摘要）；请用户 **换名**，或用户**显式确认「作为全新同名议题」** 后再新建（新前缀、新目录）；确认前不得创建 |

壳层查重口径见 [kb-change-directory-id.md](kb-change-directory-id.md)。

## 6. Wikilink 扫描语义（`--scan-wikilinks`）

在 `knowledge/` 下 Markdown 中检索是否仍引用待删目标，例如：

- 目录相对路径片段
- `变更/归档/<dirname>` 或等价路径文本

| 结果 | 行为 |
|------|------|
| 无命中 | 可按门禁继续（dry-run 列入将删；confirm 可删） |
| 有命中 | **跳过不删**；报告列出命中文件，需人工改链或确认后再批清 |

未传 `--scan-wikilinks` 时不做该扫描（仍建议 confirm 前显式加上）。

## 7. 与相关命令边界

| 命令 | 关系 |
|------|------|
| `/kb-archive` | 归档落地；**不**删除。长期清理用本 purge。 |
| `/kb-verify-issue` | 依赖归档目录 `mv` 回进行中；purge 后**无法**对该 id 回退；tombstone 可审计。 |
| `/kb-repair` | 修半迁移 / 元数据漂移；purge **不**修半迁移。 |
