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

19 KiB
Raw Blame History

🔧 铸渊补丁指令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_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 提交闭环。