首页
/ Astro Triage 流水线中的 Bug 复现阶段:reproduce 技能从 Issue 校验到 report.md 输出的完整工作流

Astro Triage 流水线中的 Bug 复现阶段:reproduce 技能从 Issue 校验到 report.md 输出的完整工作流

2026-09-05 14:35:35作者:田桥桑Industrious

Astro 仓库内置了一套面向 AI Agent 的 bug 分诊(triage)流水线,其中 reproduce.md 定义了流水线的第一个阶段:把一个 GitHub issue 变成可在本地运行的最小复现项目,并产出供下游 Agent 使用的 report.md。本文围绕该文档的完整工作流展开——输入校验、六类提前退出条件、五类复现项目的搭建方式、复现验证步骤、服务器生命周期管理规则,以及 report.md 的输出契约,并结合 pnpm-workspace.yaml.gitignoreexamples/ 模板说明其在本仓库 monorepo 中的落地机制。读完后你可以理解 Astro 团队如何让 Agent 在有限时间预算内可靠地判定“一个 issue 是否真实可复现”。

复现阶段在整体流水线中的位置

Triage 流水线由 SKILL.md 编排,共四个阶段:

  1. Reproduce(本文主题):读取并遵循 reproduce.md,隔离上下文中执行;
  2. Diagnose:读取 diagnose.md,在 packages/ 源码中定位根因;
  3. Verify:读取 verify.md,判定行为是 bug 还是有意设计;
  4. Fix:读取 fix.md,实现最小修复、补单测、创建 changeset。

复现阶段的输出结果直接决定后续走向:issue 被跳过(host-specific、版本过旧等)→ 直接进入 Output;无法复现 → 进入 Output;成功复现 → 继续诊断阶段。

各阶段之间不共享对话上下文,唯一的上下文载体是 triageDir 目录下的 report.md。reproduce 文档对此有明确的强约束(CRITICAL):无论结果如何——即使复现失败、遇到意外错误或中途放弃——都必须写出 report.md,因为编排器和下游技能依赖该文件判断发生了什么;如果没写,整条流水线会“静默失败”。同时文档用 SCOPE 约束了本阶段的边界:只负责复现,完成工作流后立即结束,不做根因诊断、不修 bug、不派生子任务。

两个前置变量

文档定义了贯穿全流程的两个变量,可由编排器以 args 传入,也可在独立运行时从对话上下文推断:

  • triageDir — 复现项目所在的目录(例如 triage/issue-123)。未传入时应从之前的对话中推断;
  • issueDetails — GitHub API 返回的 issue 详情载荷,必须由用户显式提供或来自之前的工具调用结果;若缺失,可运行 gh issue view ${issue_number} 直接从 GitHub 拉取。

仓库侧为这套约定提供了配套支持:pnpm-workspace.yaml 的 workspace 列表中包含 'triage/*',意味着每个 triage/gh-<issue_number> 目录都会被纳入 pnpm workspace;同时 .gitignore 中有 /triage/ 条目,保证这些一次性复现项目不会污染仓库状态。

Step 1:确认 Bug 细节

首要任务是确认 issueDetails 已就位;否则直接失败——没有细节就无法分诊。拿到细节后需要仔细阅读四部分信息:

  • bug 描述,以及期望行为与实际行为的对照;
  • issue 中提供的复现步骤;
  • 环境细节,特别是 astro info 输出中的 Astro 版本;
  • 评论区中可能澄清问题的讨论。

Step 2:提前退出条件(Early Exit)

在动手复现之前,先判断该 issue 是否因“沙箱复现环境的限制”而应被跳过。命中任一条件就跳到 Step 5,在 report.md 中写明跳过原因(skip details)。

一个关键的动态规则:评论会使早期退出失效。提前退出只有在该 issue 的后续评论没有“推翻”它时才成立。文档给出的例子:若原报告者使用的是 Astro 3.0,初次运行会以 unsupported-version 退出;但在一次后续运行中,如果有评论者发布了基于最新 Astro 版本的类似复现,那么这就不再是有效的提前退出,而应继续走完整工作流。

文档明确支持的六类提前退出条件如下:

条件 标识 判定依据
非可执行报告 not-actionable issue 不是 bug 报告。该工作流只分诊 bug——功能请求、建议、讨论都不在此范围内
缺少细节 missing-details issue 缺少有效复现(见 Step 3 的复现形式列表),或缺少对用户期望结果的描述(例如 issue 模板中“期望结果”一节未填写)。两者都是成功复现和后续验证所必需的
不支持的 Astro 版本 unsupported-version bug 针对 Astro 4.x 或更早版本。从 astro info 输出或 package.json 中查找版本号
宿主平台专属问题 host-specific bug 只能在特定托管平台(Vercel、Netlify、Cloudflare、Deno Deploy 等)上复现。信号包括:issue 引用了宿主专属 adapter(@astrojs/vercel@astrojs/netlify@astrojs/cloudflare);或 bug 只“在生产环境/部署后”出现,在 dev 与本地 preview 构建中均无法复现
运行时专属问题 unsupported-runtime bug 只出现在 Bun 或 Deno 上。沙箱只支持 Node.js
维护者覆盖 maintainer-override 仓库维护者在评论中表示不应在此复现该 issue。判断评论者是否为维护者:检查 issueDetails 中该评论的 authorAssociation 字段,值为 MEMBERCOLLABORATOROWNER 即视为维护者

Step 3:搭建复现项目

每份 bug 报告都应包含某种形式的复现。复现项目放入 triageDir(例如 triage/gh-123);未提供 triageDir 时默认为 triage/gh-<issue_number>。文档按 issue 提供的复现形式分五种情况处理。

形式一:StackBlitz 项目 URL(https://stackblitz.com/edit/...

stackblitz-clone 下载到 triageDir

npx stackblitz-clone@latest <stackblitz-url> <triageDir>

形式二:StackBlitz GitHub URL(https://stackblitz.com/github/...

这是 StackBlitz 上常见的“在 StackBlitz 中打开 GitHub 仓库”的专用 URL。收到此类链接时,解析出 GitHub 的 org 与 repo 名,然后按下面的“GitHub URL”方式处理。

形式三:GitHub 仓库 URL(https://github.com/...

克隆到 triage 目录,并删除 .git 目录以避免与宿主仓库冲突:

git clone https://github.com/<owner>/<repo>.git <triageDir>
rm -rf <triageDir>/.git

若 issue 中指明了特定分支或子目录,在删除 .git 之前先 checkout 该分支,或只拷贝相关子目录。

形式四:Gist URL(https://gist.github.com/

通过 GitHub API 拉取 gist 内容以理解复现:

curl -s "https://api.github.com/gists/<gist-id>"

此时往往仍需要从零搭建一个项目(走下面的手动步骤回退路径),再把 gist 中的文件应用进去。

形式五:手动步骤(无复现 URL)

若没有提供复现 URL,则按 issue 作者给出的手动步骤操作;未指明模板时,默认使用仓库的 minimal 模板:

# 1. 列出可用的示例模板
ls examples/
# 2. 删除所选模板的 node_modules,避免 `cp -r` 出问题
rm -rf examples/<template>/node_modules
# 3. 将所选模板拷贝到 triage 目录
cp -r examples/<template> <triageDir>
# 4. 在工作区根目录重新安装,补回缺失的 node_modules 依赖
pnpm install --no-frozen-lockfile

创建后用 cat <triageDir>/package.json 验证项目落在正确位置。

为什么 pnpm install --no-frozen-lockfile 能把复现项目“接进” monorepo:从 pnpm-workspace.yaml 可以看到 'triage/*' 是 workspace glob,且配置了 preferWorkspacePackages: truelinkWorkspacePackages: true——因此复现项目(如 examples/minimal/package.json 中声明的 astro 依赖)在 workspace 根目录安装后,会优先解析到本仓库 packages/astro 的源码版本而非注册表中的已发布包。这正是 triage 工作流能够针对当前检出中的代码验证 bug 的关键;同时 --no-frozen-lockfile 允许为复现项目新增依赖(如 @astrojs/react 等集成)时更新锁文件。

复现项目搭好后,按 issue 需要最小化地改造它:

  1. 更新 astro.config.mjs 中必要的配置变更;
  2. 增改依赖或 Astro 集成(@astrojs/react 等);
  3. 增改触发 bug 的页面、组件、中间件等;
  4. 增改 issue 中提到的其他文件。

文档强调:保持复现尽可能小——只添加 issue 报告者记录为触发 bug 所必需的内容。

Step 4:在 Triage 项目中尝试复现

可使用一切可用工具——pnpm run dev|build|preview|testcurlagent-browser 等。复现验证分三步:

  1. 触发 bug:按 issue 的复现步骤操作,确认 bug 出现;
  2. 验证基线:移除或反转触发代码,确认项目在不带触发代码时工作正常。这是防止误报的保护——如果去掉触发代码项目仍然是坏的,说明问题可能出在你的环境搭建,而不是报告中的 bug;
  3. 记录观察:记录精确的错误信息与堆栈、触发问题的具体命令,以及问题是稳定复现还是间歇性的。

服务器管理规则

dev/preview 服务器经常是复现必需的,但服务器问题不能吃掉时间预算。文档给出五条硬性规则:

  • 连续两次启动失败就放弃(Bail out after 2 failed server starts)。astro dev --background 或手动服务器命令连续失败两次,停止重试,不要带着各种变体无限循环。用已有信息写报告。
  • 重启前必须先停掉旧服务器。 启动新 dev 服务器前先执行 pnpm -C <triageDir> dev stop;若无效,回退到 pkill -f "astro dev\|astro preview\|node.*entry.mjs";再失败就换一个端口(--port 4322),而不是与残留进程死磕。
  • 一轮复现就够(One reproduction run is enough)。 确认或否认 bug 之后,不要为了微调配置的再测而重启服务器。追加测试属于 diagnose 阶段,不属于这里——写完发现就继续。
  • 尽量用 astro build 而非 dev/preview。 构建期复现可以完全绕开服务器生命周期问题。只有当 bug 明确依赖运行中的服务器(HMR、运行时 SSR、请求处理)时才用 dev/preview。
  • 永远使用 Astro 的后台 dev 服务器——绝不用 & 不要用 & 后台化服务器(例如 pnpm dev &),这在 CI 中会挂起。dev 服务器生命周期统一用 pnpm -C <triageDir> dev --background / pnpm -C <triageDir> dev stop 管理。

这些规则与 SKILL.md 的全局原则一脉相承:不要在基础设施问题上卡死——服务器起不来、端口被占、CI 环境缺工具时,两次尝试后就用已有数据写报告;一份带着扎实发现的“部分报告”,永远比因耗尽时间在僵死进程上而交不出报告更有价值。

Step 5:写出 report.md

report.md 写到 triage 目录中。它的定位很明确:写给下一个 LLM 阶段看的详细内部报告,不是写给人看的——下游技能访问不到原始 issue,report.md 是它们唯一的上下文来源。因此要写得详尽,包含:

  • 原始 issue 的标题、描述及 issue 正文中一切相关细节。“包含太多上下文”永远好过“太少”,没人知道哪条信息会在后续(例如在代码库中找修复)时派上用场;
  • 完整的环境细节;
  • 所有已尝试的步骤及其结果;
  • 完整的错误信息与堆栈;
  • 对代码库的观察、关于根因的猜想;
  • 任何能让下一阶段工作更快的信息。

报告还必须包含日后由 comment 技能生成最终 GitHub 评论所需的全部信息:

  • 环境细节(包版本、Node.js 版本、包管理器);
  • 复现步骤(编号列表);
  • 期望结果与实际结果的对照;
  • 错误信息与堆栈;
  • 该 issue 是被复现未复现还是跳过(以及原因)。

从下游技能可以印证这份契约的分量:diagnose.md 第一步就是读 report.md,未复现/跳过时直接追加 “DIAGNOSIS SKIPPED: No reproduction”;fix.md 则在未复现时追加 “FIX SKIPPED: Not reproduced” 并返回 fixed: false。所有阶段都只读、只追加同一个文件,形成一条以 report.md 为总线的单向信息流。

仓库中的可验证证据

这份工作流不是停留在纸面的提示词,仓库中有多处相互印证的实现与验证设施:

  • workspace 接线pnpm-workspace.yaml 中的 'triage/*' glob 加上 preferWorkspacePackages: true / linkWorkspacePackages: true,使 triage/gh-<n> 下的复现项目在 workspace 根目录执行 pnpm install --no-frozen-lockfile 后链接到 packages/ 下的源码;
  • 目录可丢弃性.gitignore 中的 /triage/.compiler/ 条目,保证复现项目与可选克隆的编译器源码(withastro/compiler,供 diagnose.mdverify.md 在涉及 .astro 文件转换时查阅)都不进入版本历史;
  • 默认模板examples/minimal/ 即“手动步骤”回退路径的默认起点,其 package.json 声明 node >= 22.12.0astro 依赖,对应 fix 阶段要求运行时代码面向 Node.js >=22.12.0 的约束;
  • 技能评测evals/evals.json 中第 2 条评测(“Runtime binding is undefined only after deploying to Cloudflare Pages”)直接验证了本文 Step 2 的 host-specific 提前退出:断言要求 triage/evals/cloudflare-binding/report.md 存在且明确分类为 host-specific 跳过,且不得执行任何项目搭建、安装、构建、起服务器或诊断动作——正是“命中提前退出后跳过 Step 3/4、直接写 report.md”这一流程的自动化验证。

小结

reproduce.md 是 Astro triage 流水线的守门阶段,其设计要点可以归纳为四条:输入校验不通过就失败、命中六类提前退出条件就快速止损并如实记录;复现项目按 issue 提供的五种形式(StackBlitz URL、StackBlitz GitHub URL、GitHub URL、Gist、手动步骤)落到 triageDir,并通过 workspace 机制链接到本仓库源码;复现验证遵循“触发—基线—记录”三步与严格的服务器管理规则,防止在僵死进程上耗尽预算;最终无论成败,report.md 都必须承载 issue 全量上下文、环境细节、步骤结果与错误证据,成为 diagnose、verify、fix 各阶段以及最终 GitHub 评论的唯一事实来源。理解这套契约,就能理解 Astro 如何用可验证的 Agent 技能把“issue 是否可复现”变成一个有明确边界、可评测、可追溯的自动化环节。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.83 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
987
506
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384