Guanghu Domestic Migration a27e87cb99 chore: import sanitized domestic snapshot for REPO-007
Source snapshot: 97d7f0fae96dc04b7ddad56fc1db6a108ed662cc

[SEC-CLEAN] · pre-push-clean v1.0 · 109处敏感信息已自动转乱码
2026-07-17 15:59:55 +08:00

544 lines
19 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 🔧 铸渊补丁指令SYSLOG自助闭环 · Issue实时进度 + 意图路由修复2026-03-13·曜冥签发
> **签发人**:曜冥(冰朔口述 · 曜冥架构设计)
>
> **执行人**铸渊GitHub 侧全量修复)
>
> **签发时间**2026-03-14T00:00+08:00
>
> **优先级**P0 · 紧急修复
>
> **关联系统**SYSLOG 自助提交系统 + 全自动闭环 v1.0
>
> **问题来源**:冰朔实测 Issue #92 发现两个 bug
>
---
## 🧠 第零步|恢复核心大脑(必须先做,否则不准动代码)
<aside>
🚨
**铸渊,你是一次性实例,每次醒来什么都不记得。**
在你动手修任何代码之前,你必须先完成以下三件事,否则你不知道自己在修什么。
</aside>
### 0-A恢复核心大脑
你的人格体档案和系统记忆存储在仓库中。先读取以下文件,恢复你对整个系统的认知:
```bash
# 必读文件(按顺序):
cat personas/zhu-yuan/profile.md # 你自己是谁、你的职责边界
cat personas/zhu-yuan/core-brain.md # 你的核心大脑 prompt / 系统指令
cat README.md # 仓库整体说明
cat docs/system-architecture.md # 系统架构总览(如果存在)
```
**目标**:读完后你应该知道——
- 你是铸渊ICE-GL-ZY001零点原核频道的 GitHub 守护层人格体
- 你的主控人是冰朔TCS-0002∞架构由曜冥设计
- 整个系统包含多个人格体(曜冥、霜砚、知秋、铸渊等),各自分管不同层
- 你负责的是 GitHub 侧的自动化 workflow、Issue 处理、代码仓库守护
### 0-B理解「SYSLOG 自助提交系统」是什么
这是你正在维护的核心系统之一。先读取相关文档和代码:
```bash
# 必读文件:
cat docs/syslog-system.md # SYSLOG 系统说明文档(如果存在)
cat .github/workflows/syslog-auto-pipeline.yml # 闭环主 workflow
cat scripts/syslog-handler.js # 或对应的处理脚本
cat data/dev-status.json # 开发者状态数据
```
**目标**:读完后你应该知道——
- SYSLOG = 开发者通过 GitHub Issue 提交系统开发日志的协议v4.0
- 自助闭环 = 开发者提交 Issue → 铸渊自动处理 → 解析内容 → 调用核心大脑 → 写入 Notion → 生成广播 → 邮件通知 → 闭环确认
- 这是一个**8 步全自动流水线**,开发者只需要提交 Issue后面全部自动
### 0-C理解「开发者入口」是什么东西
你要修复的这个系统,面向的用户是**零点原核频道的 11 位开发者**DEV-001 到 DEV-014。对开发者来说
- **入口**就是 GitHub Issue开发者新建一个 Issue按 SYSLOG 格式填写内容,提交后系统自动启动闭环
- **交互界面**就是 Issue 评论区:铸渊在评论区实时反馈处理进度,开发者也可以在评论区 @铸渊 提问
- **开发者能看到的全部信息**就是 Issue 页面上的评论。所以评论区的内容质量 = 开发者体验的全部
**这就是为什么两个 bug 都很严重**
- Bug A进度卡死= 开发者提交后看到的界面是死的,不知道系统在干嘛,以为坏了
- Bug B回答牛头不对马嘴= 开发者问问题得到的是垃圾回复,失去对系统的信任
<aside>
**确认检查**:完成 0-A / 0-B / 0-C 后,在 Issue #92 评论区发一条确认:
`🧠 铸渊已恢复核心大脑,已理解 SYSLOG 闭环系统和开发者入口。开始执行修复。`
然后再往下看修复方案。
</aside>
---
## 🎯 问题描述
冰朔在 GitHub 仓库测试 SYSLOG 自助提交系统时发现两个问题:
### Bug A闭环启动后步骤卡在「等待中」不更新
**现象**Issue #92 提交 SYSLOG 后铸渊自动回复了一张「处理细节」表格8个步骤中只有「① 接收提交」显示 ✅ 已完成,其余 7 步全部停留在 ⏳ 等待中,后续再也不更新了。开发者看到的是一个死掉的表格,不知道系统到底在干什么。
**根因**:当前实现是一次性写入一张静态表格到 Issue 评论区。GitHub Issue 评论一旦发出就是静态的,不会随着 workflow 后续步骤完成而自动更新。而且 workflow 在第一步之后可能就报错退出了API 调用失败等),但表格已经发出去了,给人造成「在处理中」的错觉。
### Bug B@铸渊 提问回复牛头不对马嘴
**现象**:冰朔在 Issue 评论区提问 `@铸渊,请查询系统开发日志提交#92闭环状态。`,铸渊回复的却是「团队细节总览」——把 11 个开发者的 waiting_syslog 状态全倒出来了,完全没回答「#92 闭环到哪一步了」这个问题。
**根因**:铸渊的 Issue 评论触发 workflow 没有做意图识别,收到任何 @铸渊 的提问都走了同一个「读 dev-status.json → 输出全部数据」的逻辑。
---
## 🔧 修复方案
### 修复 A闭环进度改为「每步一条评论」实时上报
**核心思路**:不再用一张静态表格,改为每完成一步就在 Issue 评论区 **新发一条评论**。开发者刷新页面就能看到进度在动。某步失败了也能立刻看到是哪步挂的。
**实现代码(修改 `syslog-auto-pipeline.yml` 对应的处理脚本)**
```jsx
// ━━━ 实时进度上报模块 ━━━
// 文件位置建议scripts/pipeline-reporter.js
const { Octokit } = require('@octokit/rest');
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
const OWNER = 'qinfendebingshuo';
const REPO = 'guanghulab';
/**
* 每完成一步,在 Issue 评论区发一条新评论
* @param {number} issueNumber - Issue 编号
* @param {number} stepNum - 步骤编号1-8
* @param {string} stepName - 步骤名称
* @param {'ok'|'error'|'skip'} status - 步骤状态
* @param {string} detail - 详情说明
*/
async function reportStep(issueNumber, stepNum, stepName, status, detail) {
const icon = status === 'ok' ? '✅' : status === 'error' ? '❌' : '⏭️';
const statusText = status === 'ok' ? '已完成' : status === 'error' ? '失败' : '跳过';
const body = [
`${icon} **步骤 ${stepNum}/8 · ${stepName}** · ${statusText}`,
'',
detail,
'',
`——铸渊ICE-GL-ZY001· ${new Date().toISOString()}`
].join('\n');
await octokit.issues.createComment({
owner: OWNER,
repo: REPO,
issue_number: issueNumber,
body: body
});
}
/**
* 闭环完成时发最终汇总
*/
async function reportComplete(issueNumber, success, summary) {
const icon = success ? '🎉' : '⚠️';
const title = success ? '闭环处理完成' : '闭环处理异常';
const body = [
`## ${icon} ${title}`,
'',
summary,
'',
success ? '> 新广播已生成,结果将发送到您的邮箱。' : '> 部分步骤异常,已记录日志。冰朔会在下次巡检时处理。',
'',
`——铸渊ICE-GL-ZY001· ${new Date().toISOString()}`
].join('\n');
await octokit.issues.createComment({
owner: OWNER,
repo: REPO,
issue_number: issueNumber,
body: body
});
}
module.exports = { reportStep, reportComplete };
```
**在主流程中的调用方式(修改 syslog-auto-pipeline 的主处理逻辑)**
```jsx
// ━━━ 主闭环流程(改造后)━━━
const { reportStep, reportComplete } = require('./pipeline-reporter');
async function runPipeline(issueNumber, submissionContent) {
let success = true;
let summary = [];
try {
// ① 接收提交(这步在 workflow trigger 时就完成了)
await reportStep(issueNumber, 1, '接收提交', 'ok',
'系统已收到您的 SYSLOG 提交');
// ② 解析内容
let parsed;
try {
parsed = parseSubmission(submissionContent);
await reportStep(issueNumber, 2, '解析内容', 'ok',
`广播编号: ${parsed.broadcastId} · 类型: ${parsed.type} · 邮箱: ${parsed.email}`);
} catch (e) {
await reportStep(issueNumber, 2, '解析内容', 'error',
`解析失败: ${e.message}\n请检查提交格式是否正确需包含广播编号、类型、邮箱、内容`);
throw e;
}
// ③ 模块验证
try {
const moduleExists = await checkModuleInRepo(parsed.broadcastId);
await reportStep(issueNumber, 3, '模块验证', moduleExists ? 'ok' : 'skip',
moduleExists
? `模块代码已在仓库中确认`
: `模块代码未检测到(不影响闭环继续)`);
} catch (e) {
await reportStep(issueNumber, 3, '模块验证', 'error', `验证异常: ${e.message}`);
// 模块验证失败不阻断流程,继续
}
// ④ 唤醒核心大脑(调用 Claude API
let llmResult;
try {
const systemPrompt = await buildSystemPrompt(parsed.type, parsed.devId, parsed.broadcastId);
await reportStep(issueNumber, 4, '唤醒核心大脑', 'ok',
'正在调用人格体处理 SYSLOG…预计 30-90 秒)');
llmResult = await callLLM(systemPrompt, submissionContent);
await reportStep(issueNumber, 4, '核心大脑响应', 'ok',
`人格体已完成处理 · 输出长度: ${llmResult.length} 字符`);
} catch (e) {
await reportStep(issueNumber, 4, '唤醒核心大脑', 'error',
`API 调用失败: ${e.message}\n\n请检查 Secrets: LLM_API_KEY / LLM_BASE_URL 是否配置正确`);
success = false;
throw e;
}
// ⑤ 创建概念工单(写入 Notion
try {
await writeNotionTicket(parsed, llmResult);
await reportStep(issueNumber, 5, '创建概念工单', 'ok',
'已写入霜砚工单簿');
} catch (e) {
await reportStep(issueNumber, 5, '创建概念工单', 'error',
`Notion API 写入失败: ${e.message}\n\n请检查 Secret: NOTION_TOKEN 是否有效`);
// 工单写入失败不阻断,继续尝试邮件
}
// ⑥ 生成广播
try {
const broadcast = extractBroadcast(llmResult);
await saveBroadcast(parsed.devId, broadcast);
await reportStep(issueNumber, 6, '生成广播', 'ok',
`新广播已生成 · 已存入 broadcasts-outbox/${parsed.devId}/`);
} catch (e) {
await reportStep(issueNumber, 6, '生成广播', 'error',
`广播生成/保存失败: ${e.message}`);
success = false;
}
// ⑦ 邮件通知
try {
await sendEmail(parsed.email, parsed.broadcastId, llmResult);
await reportStep(issueNumber, 7, '邮件通知', 'ok',
`结果已发送至 ${parsed.email}`);
} catch (e) {
await reportStep(issueNumber, 7, '邮件通知', 'error',
`邮件发送失败: ${e.message}\n\n请检查 Secrets: SMTP_USER / SMTP_PASS`);
}
// ⑧ 闭环确认
await reportComplete(issueNumber, success,
success
? `广播编号: ${parsed.broadcastId}\n开发者: ${parsed.devId}\n新广播已生成并推送`
: `部分步骤失败,请查看上方各步骤详情`);
} catch (e) {
// 全局兜底:确保任何未捕获的错误也会上报
await reportComplete(issueNumber, false,
`闭环中断: ${e.message}\n\n请检查 Actions 运行日志获取详细错误信息`);
}
}
```
**关键改动总结**
- ❌ 删除:一次性贴静态表格的逻辑
- ✅ 新增:`reportStep()` 每步发一条评论
- ✅ 新增:`reportComplete()` 最终汇总
- ✅ 新增:每步 try-catch失败了也上报具体错误信息不会静默挂掉
---
### 修复 B@铸渊 提问加意图路由
**核心思路**:收到 Issue 评论中的 @铸渊 提问时,先解析意图,再走对应的处理逻辑。
**实现代码(修改 Issue comment 触发的 workflow 处理脚本)**
```jsx
// ━━━ 意图路由模块 ━━━
// 文件位置建议scripts/intent-router.js
/**
* 解析用户在 Issue 评论中 @铸渊 的意图
* @param {string} commentBody - 评论原文
* @returns {object} 意图对象
*/
function parseIntent(commentBody) {
// 去掉 @铸渊 前缀,提取核心内容
const content = commentBody.replace(/@铸渊[,]?\s*/g, '').trim();
// 意图1查询某个 Issue 的闭环状态
// 匹配:「查询#92闭环状态」「#92进度」「Issue 92 状态」等
const issueMatch = content.match(/#(\d+)/);
if (issueMatch && content.match(/闭环|状态|进度|处理/)) {
return {
type: 'check_pipeline_status',
issueNumber: parseInt(issueMatch[1]),
raw: content
};
}
// 意图2查询某个开发者的状态
// 匹配「DEV-004状态」「之之进度」「查询肥猫」
const devMatch = content.match(/DEV-(\d+)|页页|肥猫|燕樊|之之|小草莓|花尔|桔子|匆匆那年|Awen|小兴|时雨/);
if (devMatch && content.match(/状态|进度|查询/)) {
return {
type: 'check_dev_status',
devId: devMatch[0],
raw: content
};
}
// 意图3团队总览显式请求
// 匹配:「团队状态」「全部进度」「总览」
if (content.match(/团队|全部|总览|所有人/)) {
return {
type: 'team_overview',
raw: content
};
}
// 意图4未识别 → 用 Claude API 理解(如果配了的话)
// 否则返回「不理解」
return {
type: 'unknown',
raw: content
};
}
/**
* 根据意图路由到对应处理逻辑
*/
async function handleIntent(intent, issueNumber) {
switch (intent.type) {
case 'check_pipeline_status': {
// 查询该 Issue 对应的 workflow run 状态
const runs = await octokit.actions.listWorkflowRunsForRepo({
owner: OWNER,
repo: REPO,
event: 'issues', // 或 'discussion'
});
// 从 Issue 评论历史中提取铸渊已发的进度评论
const comments = await octokit.issues.listComments({
owner: OWNER,
repo: REPO,
issue_number: intent.issueNumber
});
// 筛选铸渊的进度评论(包含「步骤 X/8」的
const progressComments = comments.data.filter(c =>
c.body.includes('步骤') && c.body.includes('铸渊')
);
if (progressComments.length === 0) {
return `📋 **Issue #${intent.issueNumber} 闭环状态查询**\n\n` +
`未找到该 Issue 的闭环进度记录。\n` +
`可能原因:闭环尚未启动,或该 Issue 不是 SYSLOG 提交。`;
}
// 提取最后一条进度评论,判断当前到哪一步了
const lastProgress = progressComments[progressComments.length - 1];
const stepMatch = lastProgress.body.match(/步骤 (\d+)\/8/);
const lastStep = stepMatch ? parseInt(stepMatch[1]) : 0;
const isComplete = lastProgress.body.includes('闭环处理完成') || lastStep === 8;
const hasFailed = progressComments.some(c => c.body.includes('❌'));
let statusLine;
if (isComplete && !hasFailed) {
statusLine = '✅ 闭环已完成';
} else if (hasFailed) {
statusLine = '❌ 闭环有步骤失败(详见上方各步骤评论)';
} else {
statusLine = `⏳ 闭环进行中 · 已完成到步骤 ${lastStep}/8`;
}
return `📋 **Issue #${intent.issueNumber} 闭环状态**\n\n` +
`${statusLine}\n` +
`进度评论数: ${progressComments.length}\n` +
`最后更新: ${lastProgress.created_at}`;
}
case 'check_dev_status': {
// 从 dev-status.json 中只提取该开发者的数据
const devStatus = await loadDevStatus();
const dev = devStatus.find(d =>
d.id === intent.devId || d.name === intent.devId
);
if (!dev) {
return `未找到开发者 ${intent.devId} 的记录。`;
}
return `📊 **${dev.id} ${dev.name} · 当前状态**\n\n` +
`模块: ${dev.module}\n` +
`状态: ${dev.status}\n` +
`连胜: ${dev.streak}`;
}
case 'team_overview': {
// 只有显式请求团队总览时才走这个逻辑
const devStatus = await loadDevStatus();
return formatTeamOverview(devStatus);
}
case 'unknown': {
return `🤔 我没理解你的问题。你可以试试:\n\n` +
`- \`@铸渊 查询#92闭环状态\` — 查某个提交的处理进度\n` +
`- \`@铸渊 DEV-004状态\` — 查某个开发者的进度\n` +
`- \`@铸渊 团队总览\` — 查所有人的状态`;
}
}
}
module.exports = { parseIntent, handleIntent };
```
**在 workflow 中的调用方式**
```yaml
# .github/workflows/issue-comment-handler.yml
# 或在现有的评论触发 workflow 中修改
- name: Route intent and reply
env:
GITHUB_TOKEN: $ secrets.GITHUB_TOKEN
run: |
node -e "
const { parseIntent, handleIntent } = require('./scripts/intent-router');
const comment = process.env.COMMENT_BODY;
const issueNumber = process.env.ISSUE_NUMBER;
const intent = parseIntent(comment);
console.log('[意图识别]', JSON.stringify(intent));
const reply = await handleIntent(intent, issueNumber);
// 发评论回复
await octokit.issues.createComment({
owner: 'qinfendebingshuo',
repo: 'guanghulab',
issue_number: issueNumber,
body: reply + '\n\n——铸渊ICE-GL-ZY001'
});
"
```
---
## 🔍 附加排查:闭环为什么卡在第一步
铸渊在修复上述两个 bug 的同时,**必须先排查 Issue #92 的 workflow 为什么卡住**
```bash
# 排查步骤(按顺序执行):
# 1. 查看 Actions 运行日志
# GitHub → Actions → 找到 Issue #92 触发的 workflow run → 查看 logs
# 重点看哪一步报错退出了
# 2. 检查 Secrets 是否配置完整
# 以下 Secrets 必须全部存在且有效:
# - LLM_API_KEY第三方平台密钥
# - LLM_BASE_URL第三方平台 API 地址)
# - NOTION_TOKENntn_6753...18kQ
# - SMTP_USERQQ邮箱
# - SMTP_PASSQQ邮箱授权码
# 3. 测试 Claude API 连通性
curl -X POST "${LLM_BASE_URL}/chat/completions" \
-H "Authorization: Bearer ${LLM_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"model":"claude-3-5-sonnet","messages":[{"role":"user","content":"ping"}],"max_tokens":5}'
# 如果返回 401/403 → API Key 无效
# 如果返回 404 → Base URL 不对
# 如果返回 200 → API 没问题,问题在后续步骤
# 4. 测试 Notion API 连通性
curl -X GET "https://api.notion.com/v1/users/me" \
-H "Authorization: Bearer ${NOTION_TOKEN}" \
-H "Notion-Version: 2022-06-28"
# 如果返回 401 → Token 过期或无效
# 如果返回 200 → Notion 连通正常
```
---
## ⚡ 执行优先级
| 优先级 | 任务 | 说明 |
| --- | --- | --- |
| **P0** | 排查 #92 卡住的根因 | 先看 Actions logs确认是哪个 Secret 或 API 调用挂了 |
| **P0** | 修复 A闭环实时进度上报 | 用 `reportStep()` 替换静态表格 |
| **P1** | 修复 B意图路由 | 用 `parseIntent()``handleIntent()` 替换无脑倒数据 |
| **P2** | 补充错误处理 | 每步 try-catch + 上报具体错误信息 |
---
## 📌 约束
- **不改架构**:只修 bug不重构整个系统
- **向后兼容**:新的评论上报方式不影响已有的 Issue
- **错误必须可见**:任何步骤失败都必须在 Issue 评论区体现,不允许静默失败
- **意图路由必须有兜底**:未识别的意图返回帮助提示,不要瞎猜
---
> 🌍 曜冥签发 · 2026-03-14 · 数字地球基建紧急修复
>
> 修复完成后在 Issue #92 评论区回复确认,并重新测试一次 SYSLOG 提交闭环。
>