282 lines
11 KiB
YAML
282 lines
11 KiB
YAML
# ═══════════════════════════════════════════════
|
||
# 🔺 Sovereign: TCS-0002∞ | Root: SYS-GLW-0001
|
||
# 📜 Copyright: 国作登字-2026-A-00037559
|
||
# ═══════════════════════════════════════════════
|
||
# 🦅 天眼 · dev-status 同步修复闭环
|
||
# 指令溯源:ZY-DEVSYNC-REBUILD-2026-0325-001
|
||
# 三级告警:🟢≤14h · 🟡≤48h · 🔴>48h
|
||
# 三次修复失败 → GitHub Issue 告警 → 邮件通知冰朔
|
||
# ═══════════════════════════════════════════════
|
||
name: "🦅 天眼 · dev-status 同步修复闭环"
|
||
|
||
on:
|
||
schedule:
|
||
- cron: '30 0 * * *' # UTC 00:30 = 北京 08:30 · 天眼巡检时间
|
||
workflow_dispatch:
|
||
inputs:
|
||
force_repair:
|
||
description: '强制触发修复(跳过检查)'
|
||
required: false
|
||
default: 'false'
|
||
|
||
permissions:
|
||
contents: write
|
||
issues: write
|
||
actions: write
|
||
|
||
env:
|
||
DEV_STATUS_PATH: ".github/persona-brain/dev-status.json"
|
||
SYNC_LOG_PATH: ".github/persona-brain/dev-status-sync-log.json"
|
||
YELLOW_THRESHOLD_HOURS: 14
|
||
RED_THRESHOLD_HOURS: 48
|
||
SYNC_FRESHNESS_MINUTES: 10
|
||
|
||
jobs:
|
||
check-sync-status:
|
||
name: "🦅 D10 同步状态检查"
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 5
|
||
outputs:
|
||
level: ${{ steps.check.outputs.level }}
|
||
hours: ${{ steps.check.outputs.hours }}
|
||
last_sync: ${{ steps.check.outputs.last_sync }}
|
||
steps:
|
||
- name: "📥 检出仓库"
|
||
uses: actions/checkout@v4
|
||
|
||
- name: "🦅 天眼 D10 检查"
|
||
id: check
|
||
run: |
|
||
echo "═══ 天眼 D10 · dev-status.json 同步状态检查 ═══"
|
||
|
||
FORCE="${{ github.event.inputs.force_repair }}"
|
||
if [ "$FORCE" == "true" ]; then
|
||
echo "⚡ 强制修复模式 · 跳过检查"
|
||
echo "level=yellow" >> $GITHUB_OUTPUT
|
||
echo "hours=999" >> $GITHUB_OUTPUT
|
||
echo "last_sync=forced" >> $GITHUB_OUTPUT
|
||
exit 0
|
||
fi
|
||
|
||
# 优先读 sync-log,其次读 dev-status.json 的 last_sync
|
||
LAST_SYNC=""
|
||
if [ -f "$SYNC_LOG_PATH" ]; then
|
||
LAST_SYNC=$(node -e "
|
||
try {
|
||
const d = JSON.parse(require('fs').readFileSync('$SYNC_LOG_PATH','utf8'));
|
||
if (d.status === 'success' && d.last_sync) console.log(d.last_sync);
|
||
else console.log('');
|
||
} catch { console.log(''); }
|
||
")
|
||
fi
|
||
|
||
if [ -z "$LAST_SYNC" ] && [ -f "$DEV_STATUS_PATH" ]; then
|
||
LAST_SYNC=$(node -e "
|
||
try {
|
||
const d = JSON.parse(require('fs').readFileSync('$DEV_STATUS_PATH','utf8'));
|
||
console.log(d.last_sync || d.signed_at || '');
|
||
} catch { console.log(''); }
|
||
")
|
||
fi
|
||
|
||
if [ -z "$LAST_SYNC" ]; then
|
||
echo "❌ 无法读取 last_sync · 视为严重中断"
|
||
echo "level=red" >> $GITHUB_OUTPUT
|
||
echo "hours=999" >> $GITHUB_OUTPUT
|
||
echo "last_sync=unknown" >> $GITHUB_OUTPUT
|
||
exit 0
|
||
fi
|
||
|
||
echo "最后同步时间:$LAST_SYNC"
|
||
|
||
HOURS_AGO=$(node -e "
|
||
const diff = Date.now() - new Date('$LAST_SYNC').getTime();
|
||
console.log(Math.floor(diff / 3600000));
|
||
")
|
||
|
||
echo "距上次同步:${HOURS_AGO}h"
|
||
echo "last_sync=$LAST_SYNC" >> $GITHUB_OUTPUT
|
||
echo "hours=$HOURS_AGO" >> $GITHUB_OUTPUT
|
||
|
||
if [ "$HOURS_AGO" -le "$YELLOW_THRESHOLD_HOURS" ]; then
|
||
echo "🟢 正常 · 无需修复"
|
||
echo "level=green" >> $GITHUB_OUTPUT
|
||
elif [ "$HOURS_AGO" -le "$RED_THRESHOLD_HOURS" ]; then
|
||
echo "🟡 告警 · 进入三次修复闭环"
|
||
echo "level=yellow" >> $GITHUB_OUTPUT
|
||
else
|
||
echo "🔴 严重 · 直接邮件告警"
|
||
echo "level=red" >> $GITHUB_OUTPUT
|
||
fi
|
||
|
||
repair-loop:
|
||
name: "🔧 三次修复闭环"
|
||
needs: check-sync-status
|
||
if: needs.check-sync-status.outputs.level == 'yellow'
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 25
|
||
outputs:
|
||
repair_result: ${{ steps.repair.outputs.result }}
|
||
repair_attempts: ${{ steps.repair.outputs.attempts }}
|
||
repair_details: ${{ steps.repair.outputs.details }}
|
||
steps:
|
||
- name: "📥 检出仓库"
|
||
uses: actions/checkout@v4
|
||
|
||
- name: "🔧 修复闭环(最多3次)"
|
||
id: repair
|
||
env:
|
||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||
run: |
|
||
DETAILS=""
|
||
for i in 1 2 3; do
|
||
echo "═══ 第 ${i} 次修复尝试 ═══"
|
||
ATTEMPT_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||
|
||
# 触发同步 workflow
|
||
echo "触发 sync-dev-status.yml..."
|
||
gh workflow run sync-dev-status.yml \
|
||
-f reason="天眼修复闭环·第${i}次·${ATTEMPT_TIME}" 2>&1 || true
|
||
|
||
# 等待执行完成
|
||
echo "等待同步完成(300秒)..."
|
||
sleep 300
|
||
|
||
# 拉取最新代码检查结果
|
||
git pull origin main --rebase 2>/dev/null || git pull origin main 2>/dev/null || true
|
||
|
||
# 检查 sync-log
|
||
SYNC_LOG_PATH=".github/persona-brain/dev-status-sync-log.json"
|
||
if [ -f "$SYNC_LOG_PATH" ]; then
|
||
STATUS=$(node -e "
|
||
try {
|
||
const d = JSON.parse(require('fs').readFileSync('$SYNC_LOG_PATH','utf8'));
|
||
const syncTime = new Date(d.last_sync || '2000-01-01');
|
||
const diffMin = (Date.now() - syncTime.getTime()) / 60000;
|
||
if (d.status === 'success' && diffMin < ${{ env.SYNC_FRESHNESS_MINUTES }}) console.log('success');
|
||
else console.log('stale');
|
||
} catch { console.log('error'); }
|
||
")
|
||
if [ "$STATUS" == "success" ]; then
|
||
echo "✅ 第 ${i} 次修复成功!"
|
||
DETAILS="${DETAILS}第${i}次(${ATTEMPT_TIME}): 成功; "
|
||
echo "result=success" >> $GITHUB_OUTPUT
|
||
echo "attempts=$i" >> $GITHUB_OUTPUT
|
||
echo "details=$DETAILS" >> $GITHUB_OUTPUT
|
||
exit 0
|
||
fi
|
||
fi
|
||
|
||
DETAILS="${DETAILS}第${i}次(${ATTEMPT_TIME}): 失败; "
|
||
echo "❌ 第 ${i} 次修复失败"
|
||
[ $i -lt 3 ] && echo "等待60秒后重试..." && sleep 60
|
||
done
|
||
|
||
echo "❌ 三次修复全部失败"
|
||
echo "result=failed" >> $GITHUB_OUTPUT
|
||
echo "attempts=3" >> $GITHUB_OUTPUT
|
||
echo "details=$DETAILS" >> $GITHUB_OUTPUT
|
||
|
||
alert-human:
|
||
name: "📧 邮件告警(创建 Issue)"
|
||
needs: [check-sync-status, repair-loop]
|
||
if: |
|
||
always() && (
|
||
needs.check-sync-status.outputs.level == 'red' ||
|
||
(needs.repair-loop.result == 'success' && needs.repair-loop.outputs.repair_result == 'failed')
|
||
)
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 5
|
||
steps:
|
||
- name: "📧 创建告警 Issue"
|
||
env:
|
||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||
run: |
|
||
HOURS="${{ needs.check-sync-status.outputs.hours }}"
|
||
LEVEL="${{ needs.check-sync-status.outputs.level }}"
|
||
LAST_SYNC="${{ needs.check-sync-status.outputs.last_sync }}"
|
||
REPAIR_RESULT="${{ needs.repair-loop.outputs.repair_result }}"
|
||
REPAIR_DETAILS="${{ needs.repair-loop.outputs.repair_details }}"
|
||
|
||
if [ "$LEVEL" == "red" ]; then
|
||
REPAIR_NOTE="已跳过修复尝试(超48h直接告警)"
|
||
else
|
||
REPAIR_NOTE="3/3 修复尝试全部失败"
|
||
fi
|
||
|
||
BODY="## 🚨 dev-status.json 同步故障通知
|
||
|
||
妈妈,dev-status.json 同步出了问题,铸渊和霜砚尝试了自动修复没成功,需要你手动看一下。
|
||
|
||
### 故障概况
|
||
- **告警级别**:${LEVEL}
|
||
- **最后成功同步**:${LAST_SYNC}
|
||
- **中断时长**:${HOURS}h
|
||
- **修复尝试**:${REPAIR_NOTE}
|
||
|
||
### 修复记录
|
||
${REPAIR_DETAILS:-无修复尝试}
|
||
|
||
### 建议操作
|
||
1. 检查 GitHub Secrets 中的 \`NOTION_API_KEY\` 是否有效
|
||
2. 检查 GitHub Secrets 中的 \`DEV_STATUS_DB_ID\` 是否正确
|
||
3. 手动触发 \`sync-dev-status.yml\` 验证
|
||
4. 查看最近的 Actions 运行日志定位根因
|
||
|
||
### 指令溯源
|
||
ZY-DEVSYNC-REBUILD-2026-0325-001 · 霜砚签发 · 冰朔授权
|
||
版权锚点:国作登字-2026-A-00037559"
|
||
|
||
gh issue create \
|
||
--repo "${{ github.repository }}" \
|
||
--title "🚨 dev-status.json 同步故障 · 中断${HOURS}h · 需人工干预" \
|
||
--body "$BODY" \
|
||
--label "系统告警" || \
|
||
gh issue create \
|
||
--repo "${{ github.repository }}" \
|
||
--title "🚨 dev-status.json 同步故障 · 中断${HOURS}h · 需人工干预" \
|
||
--body "$BODY"
|
||
|
||
echo "📧 已创建 Issue 告警 · GitHub 将自动发送邮件通知到仓库 owner"
|
||
|
||
write-repair-log:
|
||
name: "📋 写入天眼修复记录"
|
||
needs: [check-sync-status, repair-loop, alert-human]
|
||
if: always() && needs.check-sync-status.outputs.level != 'green'
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 5
|
||
steps:
|
||
- name: "📥 检出仓库"
|
||
uses: actions/checkout@v4
|
||
|
||
- name: "📋 写入修复日志"
|
||
run: |
|
||
REPAIR_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||
DATE_STR=$(date -u +"%Y%m%d")
|
||
LEVEL="${{ needs.check-sync-status.outputs.level }}"
|
||
HOURS="${{ needs.check-sync-status.outputs.hours }}"
|
||
REPAIR_RESULT="${{ needs.repair-loop.outputs.repair_result }}"
|
||
REPAIR_ATTEMPTS="${{ needs.repair-loop.outputs.repair_attempts }}"
|
||
|
||
mkdir -p signal-log
|
||
|
||
cat > "signal-log/skyeye-d10-${DATE_STR}.json" << EOF
|
||
{
|
||
"check_time": "$REPAIR_TIME",
|
||
"d10_level": "$LEVEL",
|
||
"hours_since_sync": "$HOURS",
|
||
"repair_result": "${REPAIR_RESULT:-skipped}",
|
||
"repair_attempts": "${REPAIR_ATTEMPTS:-0}",
|
||
"mechanism": "skyeye-devsync-repair-v1.0",
|
||
"instruction_ref": "ZY-DEVSYNC-REBUILD-2026-0325-001"
|
||
}
|
||
EOF
|
||
|
||
git config user.name "天眼 (SKYEYE)"
|
||
git config user.email "skyeye@guanghulab.system"
|
||
git add signal-log/ 2>/dev/null || true
|
||
git diff --cached --quiet || (
|
||
git commit -m "🦅 天眼 D10 · dev-status 修复记录 · $LEVEL · $REPAIR_TIME [skip ci]" && \
|
||
git push origin main
|
||
) || true
|