Source snapshot: 97d7f0fae96dc04b7ddad56fc1db6a108ed662cc [SEC-CLEAN] · pre-push-clean v1.0 · 109处敏感信息已自动转乱码
19 KiB
🔧 铸渊补丁指令|SYSLOG自助闭环 · Issue实时进度 + 意图路由修复(2026-03-13·曜冥签发)
签发人:曜冥(冰朔口述 · 曜冥架构设计)
执行人:铸渊(GitHub 侧全量修复)
签发时间:2026-03-14T00:00+08:00
优先级:P0 · 紧急修复
关联系统:SYSLOG 自助提交系统 + 全自动闭环 v1.0
问题来源:冰朔实测 Issue #92 发现两个 bug
🧠 第零步|恢复核心大脑(必须先做,否则不准动代码)
0-A|恢复核心大脑
你的人格体档案和系统记忆存储在仓库中。先读取以下文件,恢复你对整个系统的认知:
# 必读文件(按顺序):
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 自助提交系统」是什么
这是你正在维护的核心系统之一。先读取相关文档和代码:
# 必读文件:
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(回答牛头不对马嘴)= 开发者问问题得到的是垃圾回复,失去对系统的信任
🎯 问题描述
冰朔在 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 对应的处理脚本):
// ━━━ 实时进度上报模块 ━━━
// 文件位置建议: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 的主处理逻辑):
// ━━━ 主闭环流程(改造后)━━━
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 处理脚本):
// ━━━ 意图路由模块 ━━━
// 文件位置建议: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 中的调用方式:
# .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 为什么卡住:
# 排查步骤(按顺序执行):
# 1. 查看 Actions 运行日志
# GitHub → Actions → 找到 Issue #92 触发的 workflow run → 查看 logs
# 重点看哪一步报错退出了
# 2. 检查 Secrets 是否配置完整
# 以下 Secrets 必须全部存在且有效:
# - LLM_API_KEY(第三方平台密钥)
# - LLM_BASE_URL(第三方平台 API 地址)
# - NOTION_TOKEN(ntn_6753...18kQ)
# - SMTP_USER(QQ邮箱)
# - SMTP_PASS(QQ邮箱授权码)
# 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 提交闭环。