---
name: weekly-retro
description: >
  当用户要求周复盘、周报、回顾上周工作流、判断工作流改进点时使用。
  skill 是周复盘机制的 **orchestrator**——内部调用数据采集脚本、查询
  Gitea、做 LLM pattern 分析、生成候选改进、创建/更新 issue。
  闭环载体：Gitea issue（label: weekly-retro）。issue body 含事实数据 +
  候选改进；用户在评论里选定本周要做的项；做完关 issue = closed loop。
  可被 Gitea cron / workflow_dispatch（runner mode）或 Claude 会话内的
  @weekly-retro（interactive mode）触发。
  触发短语：周复盘、周报、weekly review、weekly retro、上周回顾、本周回顾、
  这周干了什么、工作流周巡检。
  不触发：按需复盘（用 retro skill）、日报（用 daily-report）、
  跨多周分析（用 retro 加大窗口）。
---

# 周复盘技能（Orchestrator + Issue-driven 闭环）

## 与 retro skill 的差异

| 维度 | `retro` | `weekly-retro` |
|---|---|---|
| 频率 | 按需 | 每周六（Gitea cron 触发） |
| 数据 | git only | git + Gitea API + .learnings |
| 输出 | 对话 | Gitea issue（body = 事实 + 候选改进） |
| 闭环 | 无 | issue open/close lifecycle |

## 模式（mode）

skill 通过 prompt 关键字识别两种模式：

- **runner mode**（cron / workflow_dispatch）：prompt 含 `runner mode` 字样
  → 不与用户对话、不问问题、按决策树跑完输出 status 退出
- **interactive mode**（默认）：用户 @weekly-retro
  → 同决策树，但加进度提示 + 完成后给本周改进建议（无强求）

两种模式的**决策树完全相同**，只是 runner 静默、interactive 友好。

## 决策树（核心）

```
skill 启动
   │
   ▼
本 ISO 周已有 weekly-retro issue ?
   │
   ├─ NO ──► CREATE
   │
   └─ YES
        │
        ▼
   body 含「候选改进」段 ?
        │
        ├─ YES ──► NOOP
        │
        └─ NO
             │
             ▼
        有用户评论 ?
             │
             ├─ NO  ──► REPAIR
             │
             └─ YES ──► WARNING
```

| 分支 | 条件 | 动作 |
|---|---|---|
| **CREATE** | 本周无 issue | 跑数据脚本 → LLM 分析 → POST issue（body = 事实 + 候选） |
| **NOOP** | issue 存在 + 含候选段 | 输出 `NOOP: issue #N already complete` 退出 |
| **REPAIR** | issue 存在 + 缺候选段 + **无**用户评论 | LLM 分析 → PATCH body 拼候选段 |
| **WARNING** | issue 存在 + 缺候选段 + **有**用户评论 | POST `⚠️ ...` 评论提示，不动 body |

REPAIR 处理"上次跑到一半崩了"的自愈；WARNING 保护"用户已 engage"的 invariant（body 必须冻结）。

## 工作流

### Step 0: 上下文确认

- 仓库：`FFAIWorkspace/workspace`，Gitea host：`http://43.130.59.228`
- token 来源（按优先级）：`$WEEKLY_RETRO_TOKEN` → `$GITEA_API_TOKEN` → `$GITEA_TOKEN`
- 计算当前 ISO 周：`date +%G-W%V`（例如 `2026-W19`）
- 期望的 issue title：`周复盘 YYYY-Www`（**只含 ISO 周**，不含日期范围；
  详见 [.learnings/2026-05-10-rolling-window-title-idempotency-trap.md](../../.learnings/2026-05-10-rolling-window-title-idempotency-trap.md)）

### Step 1: 数据采集（subprocess 调脚本）

```bash
python3 scripts/ops/weekly-review.py
```

输出落到 `testing/reports/retros/<YYYY-Www>.md`。脚本是确定性的纯函数：拉
git log + Gitea API + 扫 `.learnings/`。**不要**让 LLM 重写这部分逻辑——
脚本快、稳、便宜。

### Step 2: 查 Gitea 找当前 ISO 周的 issue

```bash
TOKEN="${WEEKLY_RETRO_TOKEN:-${GITEA_API_TOKEN:-$GITEA_TOKEN}}"
ISO_WEEK=$(date +%G-W%V)
TARGET_TITLE="周复盘 ${ISO_WEEK}"

curl -fsS -H "Authorization: token $TOKEN" \
  "http://43.130.59.228/api/v1/repos/FFAIWorkspace/workspace/issues?state=all&labels=weekly-retro&type=issues&limit=20"
```

在结果里**精确匹配** `title == "$TARGET_TITLE"`。找到则记下 `number`。

### Step 3: 判断分支

```python
existing = find_issue_by_title(TARGET_TITLE)

if not existing:
    branch = "CREATE"
elif "## 候选改进" in existing["body"]:
    branch = "NOOP"
elif existing["comments"] > 0:
    branch = "WARNING"
else:
    branch = "REPAIR"
```

### Step 4: 执行分支

#### 4.A CREATE

1. Read `testing/reports/retros/<YYYY-Www>.md`（事实段）
2. **LLM 分析**（这一步只能 LLM 做）：
   - 从数据识别 pattern（每条绑具体 PR/run/file/branch id）
   - **强制 learning distill 评估**（见 [learning distill 必做步](#learning-distill-必做步)）
   - 生成 ≥3 个候选改进（格式见 [候选改进格式](#候选改进格式)）
3. 拼 `body = 事实 markdown + "\n\n" + "## 候选改进\n\n" + 候选段`
4. POST：

```bash
curl -fsS -X POST -H "Authorization: token $TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg t "$TARGET_TITLE" --arg b "$BODY" \
        '{title: $t, body: $b, labels: [<weekly-retro label id>]}')" \
  "http://43.130.59.228/api/v1/repos/FFAIWorkspace/workspace/issues"
```

5. 输出 `CREATED: issue #N, M candidates`

#### 4.B NOOP

输出 `NOOP: issue #N already complete` 退出。不做任何 API 写。

#### 4.C REPAIR

1. Read 报告文件
2. **LLM 分析** 同 4.A 第 2 步
3. 取现有 body，**追加** `\n\n## 候选改进\n\n<段>` 到末尾形成 `new_body`
4. PATCH：

```bash
curl -fsS -X PATCH -H "Authorization: token $TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg b "$NEW_BODY" '{body: $b}')" \
  "http://43.130.59.228/api/v1/repos/FFAIWorkspace/workspace/issues/$NUMBER"
```

5. 输出 `REPAIR: issue #N, M candidates added`

#### 4.D WARNING

POST 一条评论：

```markdown
⚠️ 检测到本 issue body 不含 `## 候选改进` 段，但已有用户评论。

可能场景：之前生成中途失败，但你已经 engage 了。skill **不会**自动
repair body（避免覆盖你已经基于的内容）。

如需补候选改进段（视严重程度）：
1. **轻量**：在 Claude 会话内 `@weekly-retro`，明确说「force REPAIR
   on issue #N，覆盖 WARNING 默认行为」；
2. **彻底**：先关闭 issue（视为本周已闭环），等下周六 cron 自动开
   下一周新 issue；本周追加内容用评论 / 新 issue 单独跟进。

如已无需补，直接关闭 issue（视为闭环）。
```

```bash
curl -fsS -X POST -H "Authorization: token $TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg b "$BODY" '{body: $b}')" \
  "http://43.130.59.228/api/v1/repos/FFAIWorkspace/workspace/issues/$NUMBER/comments"
```

输出 `WARNING: issue #N has user engagement, posted advisory comment`

### Step 5: 退出

- runner mode：直接退出
- interactive mode：summarize 做了哪一支、issue url；如果是 CREATE / REPAIR
  额外提示用户去 issue 评论选定本周要做哪几项

## 候选改进格式

每条候选 **必须**：

1. 绑到具体 id（PR 号 / run id / file path / branch name）
2. DOD 可验证
3. 1 周内可做完（>2h 拆小）
4. 标注优先级 + 预估时间：`[P0|P1|P2, 估时]`

格式：

```markdown
## 候选改进

> 本段由 weekly-retro skill 自动生成（YYYY-MM-DD，mode=create|repair）。
> 请在评论里选定本周要做哪几项（如 `confirm: 1, 3`），做完后关闭本 issue。

- **[P0, 30m] 短标题**
  证据: 具体 PR/run/file/branch id（绑死，禁空话）
  动作: 具体命令或步骤
  DOD: 可验证的完成判据

- **[P1, 1h] 第二条 ...**
- ...
```

候选数量：≥3 个。**优先深挖 2-3 个最强 pattern**，不凑数。

## learning distill 必做步

每次 CREATE / REPAIR 时，LLM 在生成候选前**必须先扫一遍** §7 列出的本周新增
`.learnings/`，按下表判定是否需要出 distill 候选：

| 触发条件（任一） | 必须输出 distill 候选 |
|---|---|
| 单周新增 ≥5 条 learning | ✅ |
| 出现 ≥3 条同主题 learning（同 trap / 同 workflow / 同 module） | ✅ |
| 任意"踩坑→解决"型 learning，且解决方案可复用 | ✅ |
| 单周仅 1-2 条、且都是一次性场景 | ❌（可不出） |

distill 候选标准格式（含目标载体）：

```markdown
- **[P1, 30m] distill N 条 ⟨主题⟩ learning 到 ⟨目标⟩**
  证据: `.learnings/YYYY-MM-DD-foo.md` / `.learnings/YYYY-MM-DD-bar.md` / ... （列具体文件名）
  动作:
    1. 读 N 条 learning 提炼共性原则
    2. 写入目标载体（`docs/standards/XX-…md` 段 / `.agents/skills/<skill>/references/…md` 段 / CLAUDE.md 短规则）
    3. 在原 learning 顶部加 `> 已 distill 到 [target](path)` 反向指针
  DOD: 目标文件含可复用规则；原 learning 有反向指针；下游 AI / 团队读 standards 即可，不需再翻 learning
```

**反例**（已避免）：2026-05 一次性积压 165 条 learning 才做 distill（PR #403）——
单次工作量爆炸 + 事故信号被噪音淹没。每周做就不会再有这种事。

## 候选必绑 id 的硬规则

| ✗ 空话 | ✓ 绑 id |
|---|---|
| "提升 CI 稳定性" | "修 `quality-gates.yml` 在 `docs/audit-system-all-modules` 反复 fail（runs 1357/1343/1335/...）" |
| "清理废弃分支" | "清理 51 个 ≥7 天无活动 branch（feature/ai-tool-grants-* 5 条 24 天等）" |
| "review .learnings" | "review 24 个本周新 .learnings（第 7 节列表），把出现 ≥3 次的 pattern 升级到 standards" |

绑不到 id 的删掉重写。

## 常见 pattern 类型（仅参考，不强求都覆盖）

1. CI 失败聚集：同 workflow + 同 branch / 同 step 反复 fail
2. 长生命 PR：>3 天未合
3. Stale branch 堆积：>30 即清理信号
4. 同文件高频变更：≥5 次说明在反复改
5. .learnings 高产出但 0 升级 skill / standards（与 [learning distill 必做步](#learning-distill-必做步) 联动，是其触发信号之一）
6. 放弃的 PR（closed without merge）：方案打死的成本
7. Deploy 时长漂移：>15 min
8. Issue 关闭速度：平均 >72h

不是每周都有 8 个。**先 2-3 个最强的**。

## 与其他 skill 的衔接

用户选定改进项后，按类型给路径：

- 代码改动 → `start-feature` 开分支
- standards / skill 升级 → `docs-main` / `skill-creator`
- 基础设施修复 → `infra-check` / `troubleshoot`
- 清理类（删 stale branches）→ 直接给命令 + 用户确认后执行

## Sanity 检查

跑前 / 跑后确认：

- [ ] token 已设（任一名字）
- [ ] 报告文件已生成（`testing/reports/retros/<YYYY-Www>.md` 存在）
- [ ] 决策树命中正确分支（输出含 `CREATE/NOOP/REPAIR/WARNING` 之一）
- [ ] 候选每条都绑具体 id，无空话
- [ ] body 操作正确（CREATE = POST，REPAIR = PATCH 追加，NOOP/WARNING 不写 body）
- [ ] 若 §7 触发 distill 阈值（≥5 条 / ≥3 同主题 / "踩坑→解决"型），候选段含 ≥1 条 distill 候选

## 禁止事项

- 不写"可能 / 也许 / 建议考虑"这种没证据的 pattern
- 候选项不能是空话（必须绑 id）
- runner mode 下不要等待用户输入
- 不修改 issue body 的事实段（只追加候选段）
- 不在已有用户评论的情况下 PATCH body（走 WARNING 分支）
- 不重复跑 `weekly-review.py` 如果同一会话已经跑过
- 同周不要创建多个 issue（idempotency 由 title 精确匹配 + label 过滤保证）

## 失败模式与回退

| 失败 | 处理 |
|---|---|
| `weekly-review.py` 报错（如 token 缺失） | 立刻退出，输出错误，不创建 issue |
| Gitea API 返回 403 | 检查 token scope（需 `write:issue` + `write:repository`），输出诊断后退出 |
| Gitea API 返回 5xx | 重试 1 次，仍失败则退出 |
| LLM 分析输出空 | 退到"我无法识别有效 pattern"评论，让人工接手 |
| issue title 重复（多个匹配） | 用最新 created_at 那条，但 log 警告（不应发生，title 应唯一） |

## 相关 learnings

- [`2026-05-09-gitea-actions-runs-api-field-quirks.md`](../../.learnings/2026-05-09-gitea-actions-runs-api-field-quirks.md)
- [`2026-05-10-gitea-secret-pat-api-opaqueness.md`](../../.learnings/2026-05-10-gitea-secret-pat-api-opaqueness.md)
- [`2026-05-10-rolling-window-title-idempotency-trap.md`](../../.learnings/2026-05-10-rolling-window-title-idempotency-trap.md)

## 架构 doc

完整流转图、生命周期、设计决策见 [`docs/ops/weekly-retro-architecture.md`](../../docs/ops/weekly-retro-architecture.md)。
