From f77d1dc2218b41479f92fa61c9757e8f19aa355c Mon Sep 17 00:00:00 2001 From: Codex Date: Tue, 14 Jul 2026 09:31:04 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20=E5=9B=BA=E5=8C=96=E6=81=A2=E5=A4=8D?= =?UTF-8?q?=E4=BC=98=E5=85=88=E4=B8=8E=E5=8D=95=E6=AC=A1=E4=BA=A4=E4=BB=98?= =?UTF-8?q?=E8=A7=84=E5=88=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .agents/skills/unidesk-gh/SKILL.md | 5 ++++- .../unidesk-gh/references/pull-requests.md | 9 +++++--- .agents/skills/unidesk-subagent/SKILL.md | 8 ++++++- .../references/gh-workflow.md | 14 ++++++++++-- docs/MDTODO/agentrun-runtime-reliability.md | 4 ++++ .../R6_Task_Report.md | 22 +++++++++++++++++++ scripts/src/gh/help.ts | 4 ++-- scripts/src/gh/pr-merge.ts | 11 ++++++++-- 8 files changed, 66 insertions(+), 11 deletions(-) create mode 100644 docs/MDTODO/details/agentrun-runtime-reliability/R6_Task_Report.md diff --git a/.agents/skills/unidesk-gh/SKILL.md b/.agents/skills/unidesk-gh/SKILL.md index f5ecfbf1..b611f056 100644 --- a/.agents/skills/unidesk-gh/SKILL.md +++ b/.agents/skills/unidesk-gh/SKILL.md @@ -27,7 +27,10 @@ GitHub issue/PR 正式读写必须走 `bun scripts/cli.ts gh ...` 或 `trans gh: - 只有需要复用或正式保留的文件才使用 `--body-file`。 - 不要把 Markdown 塞进 shell 参数。 - `gh pr create` 默认 Next 只给有界 `pr view`、`pr review-plan`、`pr preflight` 和 closeout status 下钻;不得默认提示 `preflight --full|--raw`、手工 CI/CD、mirror sync、PipelineRun 或 Argo refresh。 -- PR merge 只走 guarded `gh pr merge`;主代理按 `$unidesk-subagent` 完成 review/preflight/merge 授权判断后再执行,不把“禁止默认 Next”理解成“PR 永远不能由主代理受控合并”;只有确认 ancestry 可丢弃时才显式 `--squash`。 +- PR review 先用 `review-plan` 建立文件索引,只对需要审查的文件执行 `pr diff --file`,不得机械下钻每个文件。 +- PR merge 只走 guarded `gh pr merge`;它内建 readiness/preflight,普通已审 PR 不先机械执行独立 `pr preflight`。主代理按 `$unidesk-subagent` 完成 review 和 merge 授权判断后执行;只有确认 ancestry 可丢弃时才显式 `--squash`。 +- 功能、skill、MDTODO 报告和完成状态在 merge 前已齐备时,必须进入同一个 PR。禁止仅为补写 merge SHA、`mergedAt`、branch deletion 或重复 closeout 再开文档 PR;这些事实由 GitHub PR 和 `gh pr merge` 默认摘要保存。 +- 成功 merge 后默认摘要已披露 `mergeCommit` 和 `mergedAt`,不再机械执行 `pr view`。只有输出缺字段、merge 后出现新运行证据,或需要定点排障时才继续查询;只有用户明确要求把 merge 后新证据写回 Git 时,才创建第二个 closeout PR。 ## 常用入口 diff --git a/.agents/skills/unidesk-gh/references/pull-requests.md b/.agents/skills/unidesk-gh/references/pull-requests.md index 790f7c3b..6318d6c9 100644 --- a/.agents/skills/unidesk-gh/references/pull-requests.md +++ b/.agents/skills/unidesk-gh/references/pull-requests.md @@ -2,7 +2,7 @@ PR 工作必须使用受控 UniDesk GitHub 命令: -- review 前先用 `pr review-plan`、`pr diff --file` 和有界文件下钻。 +- review 前先用 `pr review-plan` 建立 changed-file 索引,只对需要审查的文件使用 `pr diff --file` 和有界 hunk 下钻;不得逐文件机械展开。 - 人工完整 PR 正文使用 `trans gh:/owner/repo/pr/ cat`;定点查找使用同一路由的 `rg `。 - `pr view --json body,...`、`--full` 和 `--raw` 只用于显式机器结构化披露;正文只在 `.data.pullRequest.body` 输出一次。 - `pr create` 默认 Next 只给有界 observe/review/preflight/status: @@ -13,11 +13,14 @@ PR 工作必须使用受控 UniDesk GitHub 命令: 默认不得提示 `preflight --full|--raw`、手工 CI/CD、mirror sync、创建 PipelineRun 或 Argo refresh。 - `pr preflight` 是可选只读诊断;`pr merge` 内部会自行执行 preflight。 - 主代理受控合并仍然允许: - - 主代理按 `$unidesk-subagent` 完成 review/preflight/merge 判断后使用 guarded `pr merge`; + - 主代理按 `$unidesk-subagent` 完成 review 和 merge 授权判断后使用 guarded `pr merge`; - 不得把 `pr create` Next 限制误解成“PR 永远不能人工受控合并”。 - `pr merge --merge` 默认删除已合并的同 repo head branch,清理匹配且干净的本地 `.worktree`,并快进位于 PR base branch 的本地主工作区。 - `pr merge --merge --sync-node JD01` 在支持时额外执行映射节点 source-workspace sync;当前用于 HWLAB `v0.3`。 - 只有明确需要保留合并后状态时才使用 `--keep-branch` 或 `--skip-local-closeout`。 - 只有 ancestry 和语义吸收都明确安全时才使用 squash。 +- 功能实现、skill、MDTODO 报告和完成状态在 merge 前已齐备时,必须用一个 PR 收口。不得仅为补 merge SHA、`mergedAt`、branch deletion、已合并状态或重复 closeout 再开 PR。 +- merge commit 与合并时间由 GitHub PR 事实和 `gh pr merge` 默认摘要保存,不要求回写 MDTODO 报告。成功合并后不机械执行 `pr view`;只有默认输出缺少必要字段或需要定点排障时才查询。 +- 只有 merge 后才产生新的运行面证据,并且用户明确要求将该证据写回 Git 时,第二个 closeout PR 才合理。 -Closeout 应写明 source branch、验证证据和残余风险。 +同一 PR 的 closeout 应在 merge 前写明 source branch、验证证据和残余风险。 diff --git a/.agents/skills/unidesk-subagent/SKILL.md b/.agents/skills/unidesk-subagent/SKILL.md index 69a798c9..6f60eae5 100644 --- a/.agents/skills/unidesk-subagent/SKILL.md +++ b/.agents/skills/unidesk-subagent/SKILL.md @@ -51,6 +51,12 @@ description: UniDesk 主代理调度子代理的必读技能。用户提到子 - 每个任务终态和依赖变化后重新计算可安全派发集合; - 主代理自己的审核、规划和等待不计入子代理并发量;不得用一个长期任务加主代理活动宣称已经并行; - 不得为了凑并发拆出无独立价值的日志采集、重复调查、重复实现或审核代理;并发量服从原始任务边界和成功率,不服从固定数字。 +- 运行面故障、用户原入口不可用,或凭据/配置变更导致服务退化时,必须先恢复运行面,再完成工程化: + - 主代理先冻结恢复判定标准,并保留恢复关键路径的控制权; + - 优先用既有受控入口实施最小、可逆、可验证的恢复,只有受控入口本身缺失并直接阻塞恢复时,才在关键路径修改工具; + - 通用抽象、输出优化、skill、报告和长期治理不得成为恢复门禁; + - 恢复达到用户原入口可用的标准后,主代理不得把临时恢复当作任务完成,必须继续完成用户明确要求的根因修复、工程化、PR、验证和治理; + - 与恢复根因解耦且具备独立 issue、MDTODO、worktree 和验收入口的工程化任务,必须在恢复期间立即并行派发,不得全部排到恢复之后串行执行。 - 子代理并行只用于成功率高、耦合度低、能放进独立 worktree/branch/issue/PR 的任务;共享架构方向、公共契约和同文件高冲突修改先串行定锚。 - 子代理产出的审核默认由主代理直接完成: - 用户允许子代理实施、要求并行或启用多轮审查,不等于允许调度审核子代理; @@ -62,7 +68,7 @@ description: UniDesk 主代理调度子代理的必读技能。用户提到子 - 子代理报告只承载其任务事实与结论,不能自行改写上层目标、架构取舍、优先级、主线状态或跨任务治理规则; - 主代理审阅子代理报告后,亲自把被采纳的结论写入管理性、决策性文档。 - 纯文档交付可以按 `$git-spec` 的稳定分支快路径由主代理直接 commit/push,不要求临时 branch、`.worktree` 或 PR;发现本地分叉、并行改动、分支保护或运行面影响时必须保留状态并回到隔离交付。 -- 正式 GitHub issue/PR/comment/merge 仍走 `$unidesk-gh`;子代理可以提交 PR 和写调查结论,主代理负责 review/preflight/merge,除非用户明确授权某个子代理自上线自验证。 +- 正式 GitHub issue/PR/comment/merge 仍走 `$unidesk-gh`;子代理可以提交 PR 和写调查结论,主代理负责 bounded review 和 guarded merge,独立 preflight 只用于定点排障,除非用户明确授权某个子代理自上线自验证。 - 主代理和子代理必须通过 issue/PR/comment 链接传递可复用上下文、调查结论、证据链接和下一步边界;派发前先读既有评论,prompt 中只引用链接和增量任务,不复述长结论,避免不同子代理重复调查同一事实。 - 主代理派发任何执行型子代理前必须完成以下登记;对 Artificer,全部步骤必须早于 AgentRun `create task`、`apply` 和 `dispatch`: - 创建子 issue,把主要任务、接续上下文、目标分支/worktree、范围、禁止项和验收入口写入正文; diff --git a/.agents/skills/unidesk-subagent/references/gh-workflow.md b/.agents/skills/unidesk-subagent/references/gh-workflow.md index 67b09643..f4668755 100644 --- a/.agents/skills/unidesk-subagent/references/gh-workflow.md +++ b/.agents/skills/unidesk-subagent/references/gh-workflow.md @@ -19,6 +19,16 @@ - 并发不能靠重复调查、同根因的多套实现、无独立验收价值的日志采集或默认审核代理虚增;每条并发线都必须有独立 issue、worktree、交付物和验收入口。 - 派发 CI/CD 或运行面调优子任务时,主代理不要在 prompt 或评论里反复解释历史;用 issue/comment 链接引用既有结论,把下一步限定为可由子代理自主真实触发的单步 gate,并要求子代理在该 gate 内小闭环调优到通过后再提交 PR。 +## 恢复优先与工程化并发 + +- 依赖图必须先标出运行面恢复关键路径和用户原入口恢复标准。主代理控制恢复关键路径,避免多个代理同时修改同一生产对象、恢复状态机或共享配置。 +- 恢复优先指先让用户原入口通过既有受控路径恢复到可验证状态,不表示工程化任务整体串行: + - 恢复关键路径上的最小诊断、配置修正和复测按真实依赖顺序执行; + - 与根因解耦的 CLI、reference、报告、独立仓库修复和长期治理,在具备独立 issue、MDTODO、worktree、PR 与验收入口时立即并行; + - 只有缺少受控恢复入口直接阻塞恢复时,才允许把工具修改放到恢复关键路径。 +- 运行面恢复后,主代理继续完成根因修复、持久化配置、自动交付、原入口复测和治理收口;不得以临时恢复或单次手工成功代替用户要求的终态。 +- 恢复期间降低并发必须有具名原因,例如共享生产对象、同一状态机、权限边界或运行面容量;原因解除后立即重新计算可安全并发窗口。 + ## 模型与思考等级 - Artificer 默认不显式覆盖模型: @@ -71,7 +81,7 @@ - 先看架构约束和倒退风险,再看实现细节; - 重点检查是否重新引入旧 authority、并行请求源、裸 API 绕过、隐藏默认、阈值硬编码或降低探针能力; - 默认不再派审核子代理。 -- 合并前使用 `$unidesk-gh` 的 review/preflight/merge 入口。独立 PR 可以并行 review;有依赖的 PR 按契约基线、实现、验证工具、closeout 的顺序合并。 +- 合并前使用 `$unidesk-gh` 的 bounded review 和 guarded merge 入口;`pr merge` 已内建 preflight,普通已审 PR 不机械重复执行独立 `pr preflight`。独立 PR 可以并行 review;有依赖的 PR 按契约基线、实现、验证工具、closeout 的顺序合并。 - 子代理 PR 合并后,主代理负责同步目标 worktree、触发受控 CI/CD、执行原入口复测,并把 PipelineRun、GitOps revision、observer、trace、report SHA 等证据写回 issue。 - 若用户明确让子代理“自己上线自己验证”,子代理可以执行受控 CI/CD 和原入口验证,但必须在 issue/PR 留下完整证据;主代理仍要抽查并最终汇总。 @@ -96,7 +106,7 @@ Prompt 至少包含以下字段,按任务裁剪: 4. 计算当前可安全并发窗口并同时派发全部已就绪的低耦合子任务;共享契约先派一个基线任务。 - Artificer 的 `create task`、`apply` 和 `dispatch` 均只能发生在 MDTODO 登记之后。 5. 轮询子代理结果:子 issue comment、PR、验证摘要、阻塞;任一任务终态或依赖变化后立即重新计算窗口并补派,不能退化为长期单任务等待。 -6. 对每个 PR 做架构 review、bounded diff、preflight 和必要本地验证。 +6. 对每个 PR 做架构 review、bounded diff 和必要本地验证;只有定点排障时单独执行 preflight,正常收口直接使用内建 readiness 的 guarded merge。 7. 按依赖顺序合并;合并后同步目标 worktree。 8. 触发受控 CI/CD 或让明确授权的子代理上线;主代理核对 closeout。 9. 用原入口复测;把剩余问题拆到新 issue 或追加既有 issue。 diff --git a/docs/MDTODO/agentrun-runtime-reliability.md b/docs/MDTODO/agentrun-runtime-reliability.md index 9e188421..6f8edad6 100644 --- a/docs/MDTODO/agentrun-runtime-reliability.md +++ b/docs/MDTODO/agentrun-runtime-reliability.md @@ -117,3 +117,7 @@ ### R5.7 解决 [UniDesk #1957](https://github.com/pikasTech/unidesk/issues/1957):修复 Artificer resource bundle 缺失 `$post-task` skill 与 `$unidesk-subagent` 权威收口引用不一致;只沿 owning skill source、AipodSpec、resource bundle 和 runner 投影定位并物化,禁止 prompt 复制规则、手工 Pod/宿主补文件、第二 bundle authority 或人工 CI/CD,完成任务后以真实 Artificer follow-up 加载 `$post-task` 验收,完成任务后将详细报告写入[任务报告](./details/agentrun-runtime-reliability/R5.7_Task_Report.md)。 + +## R6 [completed] + +将“先恢复运行面再工程化”固化为 unidesk-subagent 的泛化主线规则:运行面恢复关键路径由主代理控制,低耦合工程化任务及时并行,恢复后继续完成工程化交付;将单 PR 收口、复用 guarded merge 内建 preflight、避免仅补 merge SHA 的重复 PR 和减少碎片化 GitHub 查询固化到 unidesk-gh 及相关 reference,并让 merge 默认摘要直接披露 merge commit 与 mergedAt,完成任务后将详细报告写入[任务报告](./details/agentrun-runtime-reliability/R6_Task_Report.md)。 diff --git a/docs/MDTODO/details/agentrun-runtime-reliability/R6_Task_Report.md b/docs/MDTODO/details/agentrun-runtime-reliability/R6_Task_Report.md new file mode 100644 index 00000000..40d6625b --- /dev/null +++ b/docs/MDTODO/details/agentrun-runtime-reliability/R6_Task_Report.md @@ -0,0 +1,22 @@ +# R6 任务报告 + +## 结论 + +已将“先恢复运行面,再工程化”固化为子代理调度的泛化原则:主代理冻结恢复标准并控制恢复关键路径,优先通过既有受控入口做最小、可逆、可验证的恢复;恢复不再阻塞低耦合工程化任务并行,运行面恢复后仍继续完成根因修复、PR、验证与治理收口。 + +已将减少重复交付固化到 GitHub skill 与 PR reference:review-plan 只建立索引并按需下钻,guarded merge 内建 preflight,功能、skill、MDTODO 报告和完成状态应在同一 PR 收口,禁止仅为补 merge SHA、mergedAt 或重复 closeout 创建第二个 PR。只有 merge 后产生新运行证据且用户明确要求写回 Git 时,才允许第二个 closeout PR。 + +已更新 GitHub merge 默认文本摘要,成功合并直接披露 mergeCommit 与 mergedAt,并取消机械 pr view 的 Next 提示。 + +## 验证 + +- unidesk-subagent skill quick_validate:通过。 +- unidesk-gh skill quick_validate:通过。 +- bun --check scripts/src/gh/pr-merge.ts:通过。 +- bun scripts/cli.ts check --syntax-only:11 项通过,0 项失败。 +- renderer 定向验证:成功输出包含 mergeCommit=abc123 与 mergedAt=2026-07-14T10:00:00Z,且不包含 gh pr view。 +- git diff --check:通过。 + +## 交付边界 + +本任务不修改运行面、不新增状态库或门禁。规则、CLI、MDTODO 报告与完成状态在同一功能 PR 中交付;merge 事实由 GitHub 和受控 merge 摘要保存,不回写本报告。 diff --git a/scripts/src/gh/help.ts b/scripts/src/gh/help.ts index 88fba10f..daa53fe3 100644 --- a/scripts/src/gh/help.ts +++ b/scripts/src/gh/help.ts @@ -100,14 +100,14 @@ export function ghHelp(): unknown { "Commander brief ClaudeQQ defaults to private target 645275593 through backend-core /api/microservices/claudeqq/proxy; UNIDESK_COMMANDER_BRIEF_CLAUDEQQ_* env vars can override target, base URL, timeout, and enabled state.", "comment update/edit PATCHes /repos/{owner}/{repo}/issues/comments/{comment_id} and preserves the comment id/timeline; comment delete is supported because GitHub supports deleting issue comments, but routine wording fixes should use update/edit. issue/pr hard delete is unsupported and close is the lifecycle alternative.", "PR files is the canonical compact changed-file/stat summary. It uses GitHub REST, returns bounded file rows, additions/deletions/changes when available, truncation metadata, and a next command for full details. Raw diff patches are not emitted by default; gh pr diff --stat is a compatibility alias for the same JSON summary.", - "PR review-plan is the review-first bounded patch index. It uses GitHub REST PR files, prints changed files with additions/deletions/hunk counts/patch-line counts/default truncation flags, and emits one per-file gh pr diff --file drill-down command without creating a local worktree.", + "PR review-plan is the review-first bounded patch index. It uses GitHub REST PR files, prints changed files with additions/deletions/hunk counts/patch-line counts/default truncation flags, and emits per-file gh pr diff --file drill-down commands without creating a local worktree. Use only the drill-downs needed for review; do not mechanically expand every file.", "PR diff --file reads one changed file patch from GitHub REST and prints only a bounded excerpt by default. Add --hunk N to inspect one hunk, --limit N to change displayed patch lines, or --full/--raw for explicit structured full-patch disclosure. --stat remains the no-patch file/stat compatibility path.", "PR edit/update PATCHes /repos/{owner}/{repo}/pulls/{number} through REST only, never GitHub Projects Classic GraphQL/projectCards, and returns low-noise JSON with repo, PR number, changedFields, url, and body size/SHA metadata instead of echoing the full body.", "PR view is the canonical bounded metadata summary; read remains a UniDesk compatibility alias. Human full-body reading uses `trans gh:/owner/repo/pr/ cat`, and targeted lookup uses the same route with `rg `. `--json body`, `--full`, and `--raw` are explicit structured machine disclosure only. View/read retain positional numbers, GitHub URLs, owner/repo#number shorthand, compatible --number, REST closeout fields, and on-demand GraphQL closeout metadata.", "PR preflight/closeout accept the same owner/repo#number shorthand as PR view/read so merge readiness checks do not require repeating --repo after a PR URL has already been normalized.", "PR list does not fetch mergeability or statusCheckRollup; request those closeout fields with gh pr view --json headRefName,baseRefName,mergeable,mergeStateStatus,statusCheckRollup.", "PR preflight is a low-noise read-only closeout helper for explicit diagnosis only. It combines redacted auth capability, PR branch/state metadata, mergeability, mergeStateStatus, compact status check counts, and an explicit read-only policy. It is not a required step before gh pr merge. Use --full or --raw to include all fetched status contexts.", - "PR merge is the one-command guarded write path: it reads closeout metadata itself, retries GitHub UNKNOWN/null mergeability with YAML-configured exponential backoff, refuses non-open/draft/conflicting/non-clean/failed/pending PRs, then uses GitHub REST merge. It defaults to deleting the merged same-repo head branch, cleaning the matching local .worktree when clean, and fast-forwarding the local main worktree on the PR base branch; --sync-node NODE additionally runs mapped node source-workspace sync. Use --dry-run to see the exact merge and closeout plan without writing.", + "PR merge is the one-command guarded write path: it reads closeout metadata itself, retries GitHub UNKNOWN/null mergeability with YAML-configured exponential backoff, refuses non-open/draft/conflicting/non-clean/failed/pending PRs, then uses GitHub REST merge. Its success summary includes mergeCommit and mergedAt, so a routine follow-up pr view is unnecessary. It defaults to deleting the merged same-repo head branch, cleaning the matching local .worktree when clean, and fast-forwarding the local main worktree on the PR base branch; --sync-node NODE additionally runs mapped node source-workspace sync. Use --dry-run to see the exact merge and closeout plan without writing.", ], }; } diff --git a/scripts/src/gh/pr-merge.ts b/scripts/src/gh/pr-merge.ts index 2ac346a1..16a2e664 100644 --- a/scripts/src/gh/pr-merge.ts +++ b/scripts/src/gh/pr-merge.ts @@ -169,6 +169,12 @@ export function renderPrMergeTable(result: GitHubCommandResult, fallbackDetails? : {}; const mergeMethod = result.method ?? result.mergeMethod ?? details.method; const deleteBranch = result.deleteBranch ?? details.deleteBranch; + const mergeResult = isRecord(result.mergeResult) ? result.mergeResult : {}; + const mergeCommitValue = pullRequest.mergeCommit; + const mergeCommit = isRecord(mergeCommitValue) + ? mergeCommitValue.oid + : mergeCommitValue ?? mergeResult.sha; + const mergedAt = pullRequest.mergedAt; const status = result.ok === true ? result.alreadyMerged === true ? "already-merged" @@ -198,13 +204,14 @@ export function renderPrMergeTable(result: GitHubCommandResult, fallbackDetails? ` repo=${ghText(result.repo)} title=${ghShort(ghText(pullRequest.title), 96)}`, ` blockers=${blockers.length === 0 ? "-" : blockers.join(",")} pending=${pending.length === 0 ? "-" : pending.join(",")}`, ` retry=${retry.attempts !== undefined && retry.maxAttempts !== undefined ? `${ghText(retry.attempts)}/${ghText(retry.maxAttempts)} exhausted=${ghText(retry.exhausted)}` : "-"}`, + ` mergeCommit=${ghText(mergeCommit)} mergedAt=${ghText(mergedAt)}`, ` branchDeletion=${ghText(branchDeletion.ok ?? branchDeletion.skippedReason ?? branchDeletion.attempted)}`, ` closeout localWorktree=${closeoutCell(localWorktree)} mainWorktree=${closeoutCell(mainWorktree)} nodeSyncs=${nodeSyncs.length === 0 ? "-" : nodeSyncs.map(closeoutCell).join(",")}`, "", "Next:", ]; - if (result.ok === true && result.alreadyMerged !== true && result.dryRun !== true) { - lines.push(` bun scripts/cli.ts gh pr view ${ghText(result.number ?? details.number)} --repo ${ghText(result.repo)}`); + if (result.ok === true && result.dryRun !== true) { + lines.push(" no follow-up required; merge facts are included in Summary."); } else { lines.push(` ${prMergeRetryCommand(ghText(result.repo), result.number ?? details.number, mergeMethod, deleteBranch)}`); lines.push(` bun scripts/cli.ts gh pr preflight ${ghText(result.number ?? details.number)} --repo ${ghText(result.repo)} --full`);