Source snapshot: 97d7f0fae96dc04b7ddad56fc1db6a108ed662cc [SEC-CLEAN] · pre-push-clean v1.0 · 109处敏感信息已自动转乱码
669 lines
23 KiB
Markdown
669 lines
23 KiB
Markdown
---
|
||
belongs_to:
|
||
- "[[INDEX · 铸渊·协作指令|GitHub ↔ Notion 桥接协议]]"
|
||
---
|
||
# 👁️ 铸渊指令|合并指令看守者 · Merge Watchdog — 行动类PR三次修复失败邮件告警 + 成功静默仪表盘更新(ZY-MERGE-WATCHDOG-2026-0324-001)
|
||
|
||
---
|
||
|
||
<aside>
|
||
📋
|
||
|
||
**指令编号:** ZY-MERGE-WATCHDOG-2026-0324-001
|
||
|
||
**优先级:** 🔴 P0 — 系统级监控升级
|
||
|
||
**签发人:** 冰朔(人类主权者)
|
||
|
||
**执行者:** 铸渊(GitHub CI/CD 工程人格)
|
||
|
||
**签发时间:** 2026-03-24 19:20 CST
|
||
|
||
**关联指令:** ZY-TIANYAN-AUTOFIX-2026-0324-001(天眼夜间自动修复引擎)
|
||
|
||
**版权锚点:** 国作登字-2026-A-00037559 · TCS-0002∞ 冰朔
|
||
|
||
</aside>
|
||
|
||
---
|
||
|
||
## 一、指令背景
|
||
|
||
天眼夜间自动修复引擎(v3.0)实现了 **扫描 → 分析 → 修复 → PR** 的闭环。但有一个盲区:
|
||
|
||
**PR 被合并之后,修复到底生效了没有?**
|
||
|
||
当前流程:天眼创建 PR → 冰朔晨间审阅合并 → 然后呢?**没人看。**
|
||
|
||
如果合并后的修复实际上没解决问题(比如错误根因判断偏了、修复代码只修了表象),这个 bug 就会在下一个夜间扫描中再次出现。天眼会再修一遍,再创建 PR,再合并……无限循环。
|
||
|
||
**本次升级目标:** 新增「合并指令看守者」(Merge Watchdog)—— 一个专门盯着已合并 PR 的守卫进程。它只看"行动"类(已合并的修复 PR),跟踪修复是否真正生效。三次修复仍然失败 → 邮件通知冰朔手动介入;修复成功 → 静默更新仪表盘,不打扰任何人。
|
||
|
||
<aside>
|
||
🎯
|
||
|
||
**核心理念:修好了就安静更新仪表盘。修不好三次,发邮件喊人。**
|
||
|
||
</aside>
|
||
|
||
---
|
||
|
||
## 二、系统架构
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
A["🔀 PR 被合并<br>fix/auto-repair-* 分支"] --> B["👁️ Merge Watchdog 启动<br>merge-watchdog.yml"]
|
||
B --> C["⏳ 等待下一次 Workflow 触发<br>观察修复是否生效"]
|
||
C --> D{"修复后 Workflow<br>运行结果?"}
|
||
D -->|"✅ 成功"| E["📊 静默更新仪表盘<br>标记:已修复 ✅"]
|
||
D -->|"❌ 仍然失败"| F["📝 记录失败次数<br>retry_count + 1"]
|
||
F --> G{"失败次数?"}
|
||
G -->|"< 3 次"| H["🔄 触发天眼重新修复<br>不同策略"]
|
||
H --> C
|
||
G -->|"= 3 次"| I["📧 邮件通知冰朔<br>需要手动介入"]
|
||
I --> J["📊 更新仪表盘<br>标记:⛔ 人类介入中"]
|
||
|
||
style A fill:#1a1a2e,color:#fff
|
||
style B fill:#e94560,color:#fff
|
||
style E fill:#1e5128,color:#fff
|
||
style I fill:#7b113a,color:#fff
|
||
style J fill:#533483,color:#fff
|
||
```
|
||
|
||
---
|
||
|
||
## 三、看守者运行机制
|
||
|
||
### 3.1 触发条件
|
||
|
||
看守者 **不是定时任务**,它是事件驱动的:
|
||
|
||
```yaml
|
||
on:
|
||
# 当 PR 被合并到 main 时触发
|
||
pull_request:
|
||
types: [closed]
|
||
branches: [main]
|
||
```
|
||
|
||
**只关注「行动类」PR:** 只有分支名匹配 `fix/auto-repair-*` 的已合并 PR 才会激活看守者。其他 PR(功能开发、文档更新等)直接跳过。
|
||
|
||
### 3.2 看守者核心状态机
|
||
|
||
```jsx
|
||
// 看守者为每个修复 PR 维护一个跟踪记录
|
||
const watchRecord = {
|
||
pr_number: 42,
|
||
pr_title: "[AUTO-FIX] sync-to-drive: rclone token 拼接修复",
|
||
merged_at: "2026-03-25T08:30:00+08:00",
|
||
target_workflows: ["sync-to-drive.yml"], // 这个 PR 修的是哪些 Workflow
|
||
retry_count: 0, // 当前失败次数
|
||
max_retries: 3, // 最大重试次数
|
||
status: "watching", // watching | fixed | escalated
|
||
repair_strategies_used: [], // 已使用的修复策略(避免重复)
|
||
last_check_time: null,
|
||
resolution: null // "auto_fixed" | "human_intervention"
|
||
}
|
||
```
|
||
|
||
### 3.3 观察窗口
|
||
|
||
PR 合并后,看守者不会立即判定成功或失败。它会等待目标 Workflow 的 **下一次自然触发**:
|
||
|
||
```jsx
|
||
// 观察策略
|
||
const OBSERVATION = {
|
||
// PR合并后,等待目标 Workflow 下一次运行
|
||
// 对于 cron 触发的 Workflow:等到下一个 cron 周期
|
||
// 对于 push 触发的 Workflow:合并本身就是一次 push,直接观察
|
||
|
||
// 最长观察窗口:48小时
|
||
// 超过48小时目标 Workflow 仍未运行 → 手动触发一次
|
||
max_observation_window_hours: 48,
|
||
|
||
// 运行结果判定:
|
||
// conclusion == "success" → 修复生效 ✅
|
||
// conclusion == "failure" → 修复未生效,进入重试流程
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 四、三次失败升级机制
|
||
|
||
### 4.1 每次失败使用不同修复策略
|
||
|
||
| **轮次** | **修复策略** | **Gemini 提示差异** | **失败后动作** |
|
||
| --- | --- | --- | --- |
|
||
| **第1轮**(原始修复) | 标准分析修复 | 常规 prompt:分析日志 → 定位问题 → 生成修复 | 记录失败,触发第2轮 |
|
||
| **第2轮**(换角度) | 深度根因分析 | 附加上一轮修复代码 + 失败日志,要求「上一轮修复没解决问题,请重新从头分析根因,不要沿用之前的假设」 | 记录失败,触发第3轮 |
|
||
| **第3轮**(最后机会) | 保守修复 + 降级方案 | 附加前两轮所有修复记录,要求「请提供最保守的修复方案,优先禁用出错功能并添加 skip + 告警,而非尝试修复根因」 | **三振出局 → 邮件通知人类** |
|
||
|
||
### 4.2 重试间隔
|
||
|
||
```jsx
|
||
const RETRY_TIMING = {
|
||
// 第1轮失败 → 等 1 小时后触发第2轮修复
|
||
round_2_delay_hours: 1,
|
||
// 第2轮失败 → 等 2 小时后触发第3轮修复
|
||
round_3_delay_hours: 2,
|
||
// 第3轮失败 → 立即发邮件
|
||
escalation_delay: 0
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 五、邮件通知机制(三振出局)
|
||
|
||
### 5.1 触发条件
|
||
|
||
当 `retry_count == 3` 且最后一轮修复仍然失败时,看守者发送邮件。
|
||
|
||
### 5.2 邮件发送方式
|
||
|
||
```yaml
|
||
# 使用 GitHub Actions 内置邮件或 API 通知
|
||
- name: "📧 发送人类介入通知"
|
||
uses: dawidd6/action-send-mail@v3
|
||
with:
|
||
server_address: smtp.gmail.com
|
||
server_port: 465
|
||
secure: true
|
||
username: $ secrets.MAIL_USERNAME
|
||
password: $ secrets.MAIL_PASSWORD
|
||
subject: "⛔ [光湖系统] 自动修复失败 — 需要你手动介入"
|
||
to: $ secrets.HUMAN_EMAIL # 冰朔的邮箱
|
||
from: "光湖系统 Merge Watchdog <noreply@guanghulab.com>"
|
||
html_body: |
|
||
# 邮件内容见下方模板
|
||
```
|
||
|
||
### 5.3 邮件内容模板
|
||
|
||
```html
|
||
<h2>⛔ 自动修复失败通知</h2>
|
||
<p>以下问题经过 <strong>3轮自动修复</strong> 仍未解决,需要你手动处理:</p>
|
||
|
||
<table border="1" cellpadding="8">
|
||
<tr>
|
||
<td><strong>问题 Workflow</strong></td>
|
||
<td>{workflow_name}</td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>错误类型</strong></td>
|
||
<td>{error_type}</td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>首次发现</strong></td>
|
||
<td>{first_seen_date}</td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>修复尝试</strong></td>
|
||
<td>3次(全部失败)</td>
|
||
</tr>
|
||
</table>
|
||
|
||
<h3>📋 你需要做什么:</h3>
|
||
<ol>
|
||
<li>打开仓库:<a href="{repo_url}">guanghulab 主仓库</a></li>
|
||
<li>查看最新失败日志:<a href="{latest_run_url}">点击查看</a></li>
|
||
<li>查看3轮修复记录:<a href="{watchdog_report_url}">修复报告</a></li>
|
||
<li>手动修复后推送到 main 分支</li>
|
||
<li>等待下一次 Workflow 运行验证</li>
|
||
</ol>
|
||
|
||
<h3>🧠 铸渊的分析摘要:</h3>
|
||
<ul>
|
||
<li>第1轮判断根因:{round1_root_cause}</li>
|
||
<li>第2轮判断根因:{round2_root_cause}</li>
|
||
<li>第3轮降级方案:{round3_fallback}</li>
|
||
<li>铸渊建议:{ai_suggestion}</li>
|
||
</ul>
|
||
|
||
<p style="color: gray;">— 光湖系统 · Merge Watchdog · {timestamp}</p>
|
||
```
|
||
|
||
<aside>
|
||
📧
|
||
|
||
**邮件原则:** 邮件必须告诉冰朔 **具体要做什么**,不能只说「修复失败了」。必须包含:哪个 Workflow 坏了、日志在哪里、三轮修复分别尝试了什么、铸渊建议人类从哪个方向手动修。
|
||
|
||
</aside>
|
||
|
||
---
|
||
|
||
## 六、成功静默机制
|
||
|
||
### 6.1 触发条件
|
||
|
||
目标 Workflow 运行结果为 `conclusion: "success"`。
|
||
|
||
### 6.2 静默更新仪表盘
|
||
|
||
```jsx
|
||
// 修复成功 → 只更新仪表盘,不发任何通知
|
||
const onSuccess = async (watchRecord) => {
|
||
// 1. 更新仪表盘 JSON
|
||
await updateDashboard({
|
||
workflow: watchRecord.target_workflows[0],
|
||
status: "fixed",
|
||
fixed_at: new Date().toISOString(),
|
||
fixed_by: "auto-repair",
|
||
retry_count: watchRecord.retry_count,
|
||
resolution: "auto_fixed"
|
||
});
|
||
|
||
// 2. 在修复 PR 上添加评论
|
||
await addPRComment(watchRecord.pr_number,
|
||
`✅ **Merge Watchdog 确认:修复已生效**\n` +
|
||
`目标 Workflow \`${watchRecord.target_workflows[0]}\` ` +
|
||
`运行成功。仪表盘已更新。`);
|
||
|
||
// 3. 关闭看守记录
|
||
watchRecord.status = "fixed";
|
||
watchRecord.resolution = "auto_fixed";
|
||
|
||
// ❌ 不发邮件
|
||
// ❌ 不发 Notion 通知
|
||
// ❌ 不在公告板留言
|
||
// ✅ 只有仪表盘静默更新
|
||
}
|
||
```
|
||
|
||
<aside>
|
||
🤫
|
||
|
||
**静默原则:修好了就安静。** 仪表盘更新即可,不需要通知任何人。冰朔有空了自己看仪表盘就知道。
|
||
|
||
</aside>
|
||
|
||
---
|
||
|
||
## 七、仪表盘看守者面板
|
||
|
||
在天眼仪表盘(`docs/dashboard/status.json`)中新增 `merge_watchdog` 区块:
|
||
|
||
```json
|
||
{
|
||
"merge_watchdog": {
|
||
"last_updated": "2026-03-25T09:00:00+08:00",
|
||
"active_watches": 1,
|
||
"resolved_watches": 5,
|
||
"escalated_watches": 0,
|
||
"records": [
|
||
{
|
||
"pr_number": 42,
|
||
"workflow": "sync-to-drive.yml",
|
||
"status": "fixed",
|
||
"retry_count": 0,
|
||
"merged_at": "2026-03-25T08:30:00+08:00",
|
||
"resolved_at": "2026-03-25T09:00:00+08:00",
|
||
"resolution": "auto_fixed"
|
||
},
|
||
{
|
||
"pr_number": 38,
|
||
"workflow": "token-renew.yml",
|
||
"status": "escalated",
|
||
"retry_count": 3,
|
||
"merged_at": "2026-03-24T08:00:00+08:00",
|
||
"escalated_at": "2026-03-25T02:00:00+08:00",
|
||
"resolution": "human_intervention",
|
||
"human_action": "pending"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 八、Workflow 完整模板
|
||
|
||
**文件名:** `.github/workflows/merge-watchdog.yml`
|
||
|
||
```yaml
|
||
name: "👁️ Merge Watchdog · 合并指令看守者"
|
||
|
||
on:
|
||
pull_request:
|
||
types: [closed]
|
||
branches: [main]
|
||
workflow_dispatch:
|
||
inputs:
|
||
pr_number:
|
||
description: '手动指定要观察的 PR 编号'
|
||
type: number
|
||
required: false
|
||
|
||
permissions:
|
||
actions: read
|
||
contents: write
|
||
pull-requests: write
|
||
issues: read
|
||
|
||
env:
|
||
MAX_RETRIES: 3
|
||
OBSERVATION_WINDOW_HOURS: 48
|
||
ROUND_2_DELAY_HOURS: 1
|
||
ROUND_3_DELAY_HOURS: 2
|
||
WATCHDOG_DATA: "docs/dashboard/watchdog-records.json"
|
||
|
||
jobs:
|
||
# ========================================
|
||
# Gate: 只看行动类(已合并的 auto-repair PR)
|
||
# ========================================
|
||
gate:
|
||
runs-on: ubuntu-latest
|
||
if: >
|
||
github.event.pull_request.merged == true &&
|
||
startsWith(github.event.pull_request.head.ref, 'fix/auto-repair-')
|
||
outputs:
|
||
should_watch: $ steps.check.outputs.should_watch
|
||
target_workflows: $ steps.check.outputs.target_workflows
|
||
steps:
|
||
- name: "🔍 识别修复目标"
|
||
id: check
|
||
env:
|
||
GH_TOKEN: $ secrets.DEPLOY_GITHUB_TOKEN
|
||
PR_BODY: $ github.event.pull_request.body
|
||
PR_TITLE: $ github.event.pull_request.title
|
||
run: |
|
||
echo "[Merge Watchdog] 检测到 auto-repair PR 合并"
|
||
echo "PR #$ github.event.pull_request.number : $PR_TITLE"
|
||
|
||
# 从 PR 标题/body 中提取修复的目标 Workflow
|
||
# 格式约定:PR title 包含 [AUTO-FIX] {workflow_name}: ...
|
||
WORKFLOW=$(echo "$PR_TITLE" | grep -oP '\[AUTO-FIX\] \K[^:]+' || echo "unknown")
|
||
|
||
echo "target_workflows=$WORKFLOW" >> $GITHUB_OUTPUT
|
||
echo "should_watch=true" >> $GITHUB_OUTPUT
|
||
echo "👁️ 开始看守: $WORKFLOW"
|
||
|
||
# ========================================
|
||
# 观察: 等待目标 Workflow 下一次运行
|
||
# ========================================
|
||
observe:
|
||
needs: gate
|
||
if: needs.gate.outputs.should_watch == 'true'
|
||
runs-on: ubuntu-latest
|
||
outputs:
|
||
workflow_result: $ steps.wait.outputs.result
|
||
run_url: $ steps.wait.outputs.run_url
|
||
steps:
|
||
- name: "⏳ 等待目标 Workflow 运行"
|
||
id: wait
|
||
env:
|
||
GH_TOKEN: $ secrets.DEPLOY_GITHUB_TOKEN
|
||
TARGET: $ needs.gate.outputs.target_workflows
|
||
run: |
|
||
echo "[Merge Watchdog] 等待 $TARGET 的下一次运行..."
|
||
|
||
MERGE_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
||
MAX_WAIT=172800 # 48 hours in seconds
|
||
POLL_INTERVAL=300 # 每5分钟检查一次
|
||
ELAPSED=0
|
||
|
||
while [ $ELAPSED -lt $MAX_WAIT ]; do
|
||
sleep $POLL_INTERVAL
|
||
ELAPSED=$((ELAPSED + POLL_INTERVAL))
|
||
|
||
# 查找合并后的新运行
|
||
LATEST_RUN=$(gh api \
|
||
"repos/$ github.repository /actions/runs?created=>$MERGE_TIME" \
|
||
--jq ".workflow_runs[] | select(.name | contains(\"$TARGET\"))" \
|
||
| head -1)
|
||
|
||
if [ -n "$LATEST_RUN" ]; then
|
||
CONCLUSION=$(echo "$LATEST_RUN" | jq -r '.conclusion // "pending"')
|
||
RUN_URL=$(echo "$LATEST_RUN" | jq -r '.html_url')
|
||
|
||
if [ "$CONCLUSION" = "success" ]; then
|
||
echo "result=success" >> $GITHUB_OUTPUT
|
||
echo "run_url=$RUN_URL" >> $GITHUB_OUTPUT
|
||
echo "✅ 修复已生效!"
|
||
exit 0
|
||
elif [ "$CONCLUSION" = "failure" ]; then
|
||
echo "result=failure" >> $GITHUB_OUTPUT
|
||
echo "run_url=$RUN_URL" >> $GITHUB_OUTPUT
|
||
echo "❌ 修复未生效"
|
||
exit 0
|
||
fi
|
||
# conclusion=pending → 继续等
|
||
fi
|
||
done
|
||
|
||
# 超时 → 手动触发一次
|
||
echo "result=timeout" >> $GITHUB_OUTPUT
|
||
echo "⏰ 观察窗口超时"
|
||
|
||
# ========================================
|
||
# 判定: 成功 → 静默 / 失败 → 计数+重试/告警
|
||
# ========================================
|
||
verdict:
|
||
needs: [gate, observe]
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: "📊 读取看守记录"
|
||
id: load
|
||
run: |
|
||
if [ -f "$WATCHDOG_DATA" ]; then
|
||
RECORD=$(jq ".records[] | select(.pr_number == $ github.event.pull_request.number )" "$WATCHDOG_DATA")
|
||
RETRY_COUNT=$(echo "$RECORD" | jq -r '.retry_count // 0')
|
||
else
|
||
RETRY_COUNT=0
|
||
mkdir -p docs/dashboard
|
||
echo '{"records":[]}' > "$WATCHDOG_DATA"
|
||
fi
|
||
echo "retry_count=$RETRY_COUNT" >> $GITHUB_OUTPUT
|
||
|
||
# -------- 成功路径:静默更新 --------
|
||
- name: "✅ 修复确认 — 静默更新仪表盘"
|
||
if: needs.observe.outputs.workflow_result == 'success'
|
||
run: |
|
||
echo "[Merge Watchdog] ✅ 修复已生效 — 静默更新仪表盘"
|
||
|
||
# 更新看守记录
|
||
jq --arg pr "$ github.event.pull_request.number " \
|
||
--arg now "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
||
'.records += [{
|
||
"pr_number": ($pr | tonumber),
|
||
"status": "fixed",
|
||
"resolved_at": $now,
|
||
"resolution": "auto_fixed"
|
||
}]' "$WATCHDOG_DATA" > tmp.json && mv tmp.json "$WATCHDOG_DATA"
|
||
|
||
git config user.name "Merge Watchdog"
|
||
git config user.email "watchdog@guanghulab.com"
|
||
git add "$WATCHDOG_DATA"
|
||
git commit -m "[WATCHDOG] ✅ PR #$ github.event.pull_request.number 修复已确认生效"
|
||
git push
|
||
|
||
# 在 PR 上留评论
|
||
gh pr comment $ github.event.pull_request.number \
|
||
--body "✅ **Merge Watchdog 确认:修复已生效** — 仪表盘已静默更新。"
|
||
|
||
echo "🤫 不发邮件,不通知,安静收工。"
|
||
|
||
# -------- 失败路径:计数 + 重试或告警 --------
|
||
- name: "❌ 修复未生效 — 判断重试/告警"
|
||
if: needs.observe.outputs.workflow_result == 'failure'
|
||
env:
|
||
RETRY_COUNT: $ steps.load.outputs.retry_count
|
||
GH_TOKEN: $ secrets.DEPLOY_GITHUB_TOKEN
|
||
GEMINI_API_KEY: $ secrets.GEMINI_API_KEY
|
||
run: |
|
||
NEW_COUNT=$((RETRY_COUNT + 1))
|
||
echo "[Merge Watchdog] ❌ 第 $NEW_COUNT 次失败"
|
||
|
||
if [ $NEW_COUNT -lt $ env.MAX_RETRIES ]; then
|
||
echo "🔄 触发重新修复(策略 $NEW_COUNT)"
|
||
# 根据轮次使用不同策略:
|
||
# 轮次1 → 标准修复(已用过)
|
||
# 轮次2 → 深度根因分析(附加前一轮失败信息)
|
||
# 轮次3 → 保守降级方案
|
||
|
||
# 更新看守记录
|
||
jq --arg pr "$ github.event.pull_request.number " \
|
||
--argjson count $NEW_COUNT \
|
||
'(.records[] | select(.pr_number == ($pr | tonumber))).retry_count = $count' \
|
||
"$WATCHDOG_DATA" > tmp.json && mv tmp.json "$WATCHDOG_DATA"
|
||
|
||
git config user.name "Merge Watchdog"
|
||
git config user.email "watchdog@guanghulab.com"
|
||
git add "$WATCHDOG_DATA"
|
||
git commit -m "[WATCHDOG] 🔄 PR #$ github.event.pull_request.number 第${NEW_COUNT}次修复失败,触发重试"
|
||
git push
|
||
|
||
# 触发天眼重新修复(使用 repository_dispatch)
|
||
gh api repos/$ github.repository /dispatches \
|
||
--method POST \
|
||
-f event_type="watchdog-retry" \
|
||
-f client_payload[pr_number]="$ github.event.pull_request.number " \
|
||
-f client_payload[retry_round]="$NEW_COUNT" \
|
||
-f client_payload[run_url]="$ needs.observe.outputs.run_url "
|
||
else
|
||
echo "⛔ 三振出局!发送邮件通知冰朔"
|
||
# 更新看守记录为 escalated
|
||
jq --arg pr "$ github.event.pull_request.number " \
|
||
--arg now "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
||
'(.records[] | select(.pr_number == ($pr | tonumber))) |= . + {
|
||
"status": "escalated",
|
||
"escalated_at": $now,
|
||
"resolution": "human_intervention"
|
||
}' "$WATCHDOG_DATA" > tmp.json && mv tmp.json "$WATCHDOG_DATA"
|
||
|
||
git config user.name "Merge Watchdog"
|
||
git config user.email "watchdog@guanghulab.com"
|
||
git add "$WATCHDOG_DATA"
|
||
git commit -m "[WATCHDOG] ⛔ PR #$ github.event.pull_request.number 三次修复失败,已通知人类"
|
||
git push
|
||
fi
|
||
|
||
# -------- 三振出局:发邮件 --------
|
||
- name: "📧 发送人类介入邮件"
|
||
if: >
|
||
needs.observe.outputs.workflow_result == 'failure' &&
|
||
steps.load.outputs.retry_count >= 2
|
||
uses: dawidd6/action-send-mail@v3
|
||
with:
|
||
server_address: smtp.gmail.com
|
||
server_port: 465
|
||
secure: true
|
||
username: $ secrets.MAIL_USERNAME
|
||
password: $ secrets.MAIL_PASSWORD
|
||
subject: "⛔ [光湖系统] 自动修复三次失败 — 需要手动介入"
|
||
to: $ secrets.HUMAN_EMAIL
|
||
from: "光湖 Merge Watchdog <noreply@guanghulab.com>"
|
||
html_body: |
|
||
<h2>⛔ 合并指令看守者 · 三振出局通知</h2>
|
||
<p>以下修复经过 <strong>3轮自动修复</strong> 仍未解决:</p>
|
||
<table border="1" cellpadding="8">
|
||
<tr><td><b>PR</b></td><td>#$ github.event.pull_request.number </td></tr>
|
||
<tr><td><b>目标 Workflow</b></td><td>$ needs.gate.outputs.target_workflows </td></tr>
|
||
<tr><td><b>最新失败日志</b></td><td><a href="$ needs.observe.outputs.run_url ">点击查看</a></td></tr>
|
||
</table>
|
||
<h3>📋 你需要做什么:</h3>
|
||
<ol>
|
||
<li>打开上面的失败日志链接</li>
|
||
<li>查看报错信息和上下文</li>
|
||
<li>手动修复代码并推送到 main</li>
|
||
<li>等待下一次 Workflow 运行验证</li>
|
||
</ol>
|
||
<p>看守者已暂停对该 Workflow 的自动修复。<br>
|
||
手动修复成功后,仪表盘会自动更新。</p>
|
||
<p style="color:gray;">— 光湖系统 · Merge Watchdog</p>
|
||
|
||
```
|
||
|
||
---
|
||
|
||
## 九、安全护栏
|
||
|
||
<aside>
|
||
🛡️
|
||
|
||
**看守者五条铁律**
|
||
|
||
1. **看守者自身不修改代码** — 它只观察、记录、通知。修复代码由天眼修复引擎生成
|
||
2. **最多重试 3 次** — 硬上限,不可被任何配置覆盖
|
||
3. **每轮修复策略必须不同** — 禁止用相同方法重复修复
|
||
4. **邮件必须包含具体操作步骤** — 不能只说「失败了」,必须告诉人类做什么
|
||
5. **成功后绝对静默** — 只更新仪表盘 JSON,不发邮件、不发通知、不写公告
|
||
</aside>
|
||
|
||
---
|
||
|
||
## 十、与现有系统的协作关系
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
A["🌙 天眼夜间修复引擎<br>v3.0"] -->|"创建 PR"| B["🔀 PR 合并"]
|
||
B -->|"触发"| C["👁️ Merge Watchdog<br>合并指令看守者"]
|
||
C -->|"修复成功"| D["📊 仪表盘<br>静默更新"]
|
||
C -->|"修复失败<br>< 3次"| E["🔄 repository_dispatch"]
|
||
E -->|"触发重新修复"| A
|
||
C -->|"三振出局"| F["📧 邮件通知冰朔"]
|
||
F -->|"人类手动修复"| B
|
||
|
||
style C fill:#e94560,color:#fff
|
||
style D fill:#1e5128,color:#fff
|
||
style F fill:#7b113a,color:#fff
|
||
```
|
||
|
||
<aside>
|
||
🔗
|
||
|
||
**协作链:** 天眼夜间修复 → PR → 冰朔合并 → **看守者开始盯** → 成功就安静 / 失败就重试 / 三次失败就发邮件喊人
|
||
|
||
</aside>
|
||
|
||
---
|
||
|
||
## 十一、铸渊 Secrets 配置清单
|
||
|
||
| **Secret 名称** | **用途** | **当前状态** |
|
||
| --- | --- | --- |
|
||
| `DEPLOY_GITHUB_TOKEN` | 读取 Workflow 运行记录 + 创建分支 + 推送 | ✅ 已有 |
|
||
| `GEMINI_API_KEY` | 重试修复时调用 Gemini 分析 | ✅ 已有 |
|
||
| `MAIL_USERNAME` | 发送告警邮件的 SMTP 账号 | ⚠️ 需配置 |
|
||
| `MAIL_PASSWORD` | 发送告警邮件的 SMTP 密码/应用专用密码 | ⚠️ 需配置 |
|
||
| `HUMAN_EMAIL` | 冰朔的邮箱地址(接收告警) | ⚠️ 需配置 |
|
||
|
||
<aside>
|
||
⚠️
|
||
|
||
**铸渊注意:** 邮件功能需要冰朔在 GitHub Secrets 中配置 `MAIL_USERNAME`、`MAIL_PASSWORD`、`HUMAN_EMAIL` 三个值。建议使用 Gmail 应用专用密码。如果暂时无法配置邮件,可以先用 GitHub Issue 作为替代告警方式(在仓库创建 Issue 并 assign 给冰朔)。
|
||
|
||
</aside>
|
||
|
||
---
|
||
|
||
## 十二、执行回执模板
|
||
|
||
```markdown
|
||
## 执行回执
|
||
|
||
- [ ] Workflow 文件创建:`.github/workflows/merge-watchdog.yml`
|
||
- [ ] 看守记录 JSON 初始化:`docs/dashboard/watchdog-records.json`
|
||
- [ ] 与天眼夜间修复引擎 `repository_dispatch` 联动测试
|
||
- [ ] 邮件 Secrets 配置确认(MAIL_USERNAME / MAIL_PASSWORD / HUMAN_EMAIL)
|
||
- [ ] 仪表盘面板新增 `merge_watchdog` 区块
|
||
- [ ] 手动触发测试(workflow_dispatch)
|
||
- [ ] 回执签名:铸渊 · {日期}
|
||
```
|
||
|
||
---
|
||
|
||
<aside>
|
||
🧊
|
||
|
||
**🧊 TCS-0002∞ 冰朔 · 总架构师 · 授权**
|
||
|
||
本指令由 **霜砚(PER-SY001)** 代 TCS-0002∞ 冰朔 签发。
|
||
|
||
铸渊读取后按指令执行,完成后提交执行回执。
|
||
|
||
</aside> |