From 4d7336c26d8fe86a3e3b651d877eb6b605957b1e Mon Sep 17 00:00:00 2001 From: Haitao Pan Date: Sun, 28 Jun 2026 12:45:21 +0800 Subject: [PATCH] docs: add GitHub branch model strategy + v1.1.5 release-prep record (#214) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - tldr-github-branch-model.md: 两级分支保护、release/* 发布门禁、§8 应急流程 - release-v1.1.5-preparation.md: 本轮 7 仓发布前准备完整记录 Co-authored-by: Haitao Pan Co-authored-by: Claude Opus 4.8 --- docs/release-v1.1.5-preparation.md | 127 +++++++++++++++++ docs/tldr-github-branch-model.md | 219 +++++++++++++++++++++++++++++ 2 files changed, 346 insertions(+) create mode 100644 docs/release-v1.1.5-preparation.md create mode 100644 docs/tldr-github-branch-model.md diff --git a/docs/release-v1.1.5-preparation.md b/docs/release-v1.1.5-preparation.md new file mode 100644 index 00000000..f1fe7231 --- /dev/null +++ b/docs/release-v1.1.5-preparation.md @@ -0,0 +1,127 @@ +# Release v1.1.5 — 发布前准备记录 + +> 记录 2026-06-28 一轮 7 仓发布前准备:稳定性改进收口、发布分支/Tag 创建、两级分支保护、分支模型门禁、首个 hotfix PR 审核。 +> 配套文档:分支模型策略见 [tldr-github-branch-model.md](tldr-github-branch-model.md);稳定性根因与改进见 `xworkmate-app/docs/cases/06-gateway-turn-stability-and-robustness.md`。 + +--- + +## 0. TL;DR + +- **稳定性改进全部落地**:T1–T13 + S0 + S5(四层 gateway turn 链路止血 + 持久 run 仓 + 可观测 + 插件稳定安装 + 提示精简),main 已合并并 live 验证通过。 +- **7 仓建发布分支 + Tag**:`release/v1.1.5`(分支与 Tag 同名,推送用显式 refspec)。 +- **两级分支保护**:`main` 轻保护(走 PR、禁 force-push);`release/v*` 严保护(1 review + status checks + conversation + linear history + admin 不豁免)。 +- **发布门禁**:`release/*` 仅接受 `hotfix/*` 或带 `cherry-pick`/`backport` 标签的 PR(workflow 待部署)。 +- **首个 hotfix PR #16** 审核通过(PDF 成品排序),待合并。 + +--- + +## 1. 仓库清单与发布基线 + +| 仓库 | owner/repo | remote | `release/v1.1.5` 基线 commit | +|---|---|---|---| +| xworkmate-app | `ai-workspace-lab/xworkmate-app` | SSH | `b95be41` | +| xworkmate-bridge | `ai-workspace-lab/xworkmate-bridge` | SSH | `188ca4b` | +| xworkspace-console | `ai-workspace-lab/xworkspace-console` | SSH | `3ce3c6f` | +| openclaw-multi-session-plugins | `ai-workspace-lab/openclaw-multi-session-plugins` | SSH | `849972a` | +| playbooks | `ai-workspace-infra/playbooks` | SSH | `d806ba9` | +| iac_modules | `ai-workspace-infra/iac_modules` | SSH(**已从 Cloud-Neutral-Workshop 改正**)| `e489fa7` | +| xworkspace-core-skills | `ai-workspace-lab/xworkspace-core-skills` | SSH(**已从 https 改正**)| `c6b1a03` | + +> 两处 remote 修正:`iac_modules` → `ai-workspace-infra`;`xworkspace-core-skills` → SSH(https + PAT 缺 `workflow` scope,无法写 `.github/workflows/`)。 + +--- + +## 2. 稳定性改进收口(进入 v1.1.5 的内容) + +完整根因与设计见 cases/06。本轮确认 **已合并 main 且 live 验证**: + +| 项 | 仓库 | 内容 | +|---|---|---| +| T1 | playbooks | Caddy `/acp*` 超时对齐 bridge 60min(30m→70m)| +| T2 | playbooks | 补齐非 `/acp` 路由流式配置(`flush_interval -1` + 长超时)| +| T3 | app | running 轮询加硬截止(DeadlineAt)| +| T4 | app | `停止` 本地权威化(清 pending)| +| T5 | app | 传输中断降级为「后台续跑·重连中」(有界续轮询,6 次耗尽落终态)| +| T6 | app | 失败路径与 pending 清理一致性 | +| T7/T8/T9 | bridge | 持久 per-session run 仓,脱离 WS 连接生命周期;DeadlineAt 兜底 interrupted | +| T10/T11/T12 | bridge | 错误语义(`retryable`/`poll`)+ runId 贯穿日志 + 三项指标经 `/api/ping` 暴露 | +| S0 | runtime | 插件稳定安装(真实目录 + `openclaw plugins install`),重启后 6 plugins 不丢 | +| S5 | app | gateway 提示工作区上下文精简,去除冲突的 App 本地路径 | + +**live 健康(2026-06-27/28)**:bridge 运行 commit == main HEAD(无漂移);`/api/ping.metrics` 三项均 0;网关稳定 6 plugins;四层 E2E 打通(summary.md 438B 落 task scope)。 + +### 已知 backlog(未进 v1.1.5,记录在案) +- **S1**:缺省 `expectedArtifactDirs` 兜底扫描 —— 已合并后回退(`0280893`→`81f65e3`),需解耦「扫描提示/阻塞导出」后重做。 +- **T8b**:bridge run 仓跨进程重启持久化 —— 纯增量加固,~250–350 行评估在案,未做。 + +--- + +## 3. 发布分支与 Tag + +每仓从 `main` 创建(分支与 Tag **同名** `release/v1.1.5`): + +```bash +git branch release/v1.1.5 main +git tag release/v1.1.5 main +# 同名 → 显式 refspec 推送,避免歧义 +git push origin refs/heads/release/v1.1.5:refs/heads/release/v1.1.5 \ + refs/tags/release/v1.1.5:refs/tags/release/v1.1.5 +``` + +> 本地操作同名分支/Tag 用 `git checkout refs/heads/release/v1.1.5` 消歧义。 + +--- + +## 4. 两级分支保护(已应用) + +### 4.1 `main`(轻保护,7 仓) +| 规则 | 值 | +|---|---| +| 要求 PR | ✅(`required_approving_review_count: 0`,可合自己的 PR)| +| 禁 force-push | ✅ `allow_force_pushes: false` | +| 禁删除 | ✅ `allow_deletions: false` | +| Admin 豁免 | ✅ 可绕过(`enforce_admins: false`)| +| Status checks / linear history | ❌ 不强制 | + +### 4.2 `release/v1.1.5`(严保护,7 仓) +| 规则 | 值 | +|---|---| +| 禁直接 push | ✅(走 PR)| +| 禁 force-push / 禁删除 | ✅ / ✅ | +| Admin 不豁免 | ✅ `enforce_admins: true` | +| 强制 review | `required_approving_review_count: 1` + `dismiss_stale_reviews: true` | +| Status checks | `strict: true`(contexts 待来源校验 workflow 跑出后补)| +| Conversation 解决 | ✅ `required_conversation_resolution: true` | +| Linear history | ✅ `required_linear_history: true`(禁 merge commit)| + +> API 注意:必传 `required_pull_request_reviews`/`required_status_checks`/`restrictions`(可为 `null`)否则 422;分支名 `/` 在 path 段需编码 `release%2Fv1.1.5`。 +> 写 `.github/workflows/` 需 token 带 `workflow` scope 或改走 SSH git push(当前 token scopes:`repo, read:org, project, gist, admin:public_key`,**无 workflow**)。 + +--- + +## 5. 发布门禁 — PR 来源校验 + +`release/*` 仅接受 `hotfix/*` 或带 `cherry-pick`/`backport` 标签的 PR;禁止 main/develop/feature 直入。校验靠 `.github/workflows/validate-release-pr.yml`(详见 tldr-github-branch-model.md §4)。 + +- ⏳ **状态:待部署**。因 main 现已要求 PR,需为 7 仓各开 PR 合入 workflow;现有 `release/v1.1.5` 需 backport 该 workflow 才能对其 PR 实际生效(`pull_request_target` 用 base 分支的 workflow 版本)。 + +--- + +## 6. 首个 hotfix PR 审核 + +**[PR #16](https://github.com/ai-workspace-lab/xworkmate-app/pull/16)** — `fix(artifacts): prioritize PDF deliverables in sidebar` +- 路径:`hotfix/pdf-sync-anomaly-release` → `release/v1.1.5`(✅ 合规) +- 改动:2 文件 +67/-0;排序 comparator 加 PDF 优先 + 根目录优先 +- 实证:`flutter test desktop_thread_artifact_service_test.dart` **4/4 通过**;`flutter analyze` 改动文件 **No issues** +- 结论:**通过,可合并**(单 commit,满足 linear history) +- nit(非阻塞):PDF 深度 tie-break 的 `if(a==pdf)` 隐含 b 也是 pdf,可加注释 + +--- + +## 7. 剩余动作(发布前 checklist) + +- [ ] 部署 `validate-release-pr.yml` 到 7 仓 main(走 PR) +- [ ] backport workflow 到 `release/v1.1.5`(hotfix PR),并把其 check 名加入 `required_status_checks.contexts` +- [ ] Approve + squash 合并 PR #16 +- [ ] (可选)把现有 CI check(app: `build-and-release`/`pr-tests`/`release-e2e`)按需加入 release/v* required checks +- [ ] backlog 排期:S1 重做、T8b 跨重启持久化 diff --git a/docs/tldr-github-branch-model.md b/docs/tldr-github-branch-model.md new file mode 100644 index 00000000..456ffaae --- /dev/null +++ b/docs/tldr-github-branch-model.md @@ -0,0 +1,219 @@ +# TL;DR — GitHub 分支模型与发布管理策略 + +> 适用于全部交付仓库(7 仓)。**核心思想:`main` 是「最新但不保证最稳」的集成主干,`release/v*` 是「冻结的稳定发布分支」,二者治理规则不同。** +> 首次落地:`release/v1.1.5`(2026-06-28,7 仓全部应用保护 + 来源校验)。 + +--- + +## 1. 一句话总结 + +| 分支 | 角色 | 谁能进 | 稳定性 | +|---|---|---|---| +| `main` | 集成主干,收各类已验证 PR | 任意已 review 的 PR | 最新,**不保证最稳** | +| `release/v*` | 冻结的发布快照(如 `release/v1.1.5`) | **仅** `hotfix/*` + 已验证的 cherry-pick/backport | **最稳定**,受最严保护 | +| `hotfix/*` | 针对发布分支的紧急修复 | 从 `release/v*` 切出,修完 PR 回 `release/v*`(再 backport 回 `main`) | — | +| `feature/*` | 常规功能开发 | PR → `main`(**禁止**直接进 `release/*`) | — | + +> 不设 `release/latest`——「最新发布版」由 tag/版本号语义表达,别名分支多余。 + +--- + +## 2. 受保护分支规则(`release/v*`) + +7 仓的 `release/v1.1.5` 已应用以下 GitHub Branch Protection(通过 REST API `PUT /repos/{owner}/{repo}/branches/{branch}/protection`): + +| 规则 | 设置 | 含义 | +|---|---|---| +| 禁止直接 Push | ✅(PR 强制) | 所有变更走 PR | +| 禁止 Force Push | `allow_force_pushes: false` | 历史不可改写 | +| 禁止删除分支 | `allow_deletions: false` | 发布快照不可删 | +| Admin 不豁免 | `enforce_admins: true` | 管理员也受同等约束 | +| 强制 PR Review | `required_approving_review_count: 1` | 至少 1 人批准 | +| 过期 Review 失效 | `dismiss_stale_reviews: true` | 新 push 后需重新批准 | +| 必过 Status Checks | `required_status_checks.strict: true` | 含来源校验 workflow(见 §4)| +| 必须解决 Conversation | `required_conversation_resolution: true` | 所有 review 讨论需 resolve | +| 线性历史 | `required_linear_history: true` | 禁 merge commit,仅 Squash/Rebase | + +### 一键应用(任意新 `release/vX.Y.Z`) + +```bash +TOKEN=$(gh auth token) +SLUG=ai-workspace-lab/xworkmate-app # owner/repo +BRANCH=release/vX.Y.Z + +curl -s -X PUT \ + -H "Authorization: Bearer $TOKEN" \ + -H "Accept: application/vnd.github.v3+json" \ + -d '{ + "enforce_admins": true, + "required_pull_request_reviews": {"required_approving_review_count": 1, "dismiss_stale_reviews": true}, + "required_status_checks": {"strict": true, "contexts": []}, + "required_conversation_resolution": true, + "required_linear_history": true, + "restrictions": null, + "allow_force_pushes": false, + "allow_deletions": false + }' \ + "https://api.github.com/repos/$SLUG/branches/$(python3 -c "import urllib.parse,sys;print(urllib.parse.quote(sys.argv[1],safe=''))" "$BRANCH")/protection" +``` + +> ⚠️ API 必传 `required_pull_request_reviews`/`required_status_checks`/`restrictions` 三项(可为 `null`),否则 422 `weren't supplied`。 +> ⚠️ 分支名含 `/`,URL path 段需编码为 `release%2FvX.Y.Z`。 + +--- + +## 3. 发布策略 — 什么能进 `release/v*` + +**仅接受两类合并:** +1. ✅ `hotfix/*` 分支的修复(从对应 `release/v*` 切出) +2. ✅ 已验证 Feature 的 **Cherry-pick / Backport**(PR 打 `cherry-pick` 或 `backport` 标签) + +**明确禁止:** +- ❌ 从 `develop` / `main` / `master` 直接合并 +- ❌ 从普通 `feature/*` 直接合并 + +> Branch Protection 本身无法限制「来源分支」,因此用 §4 的 GitHub Actions 在 PR 上做来源校验,作为 required status check 卡 merge。 + +--- + +## 4. PR 来源校验 Workflow(`release/*` 专用) + +GitHub Branch Protection 不能限制 PR 的源分支,故每仓部署 `.github/workflows/validate-release-pr.yml`,对 `base = release/*` 的 PR 校验来源,纳入 required status checks。 + +```yaml +name: Validate Release PR +on: + pull_request_target: + types: [opened, synchronize, reopened] +jobs: + validate-release-source: + runs-on: ubuntu-latest + if: startsWith(github.base_ref, 'release/') + steps: + - name: Check PR source branch + run: | + SRC="${{ github.head_ref }}" + LABELS="${{ join(github.event.pull_request.labels.*.name, ',') }}" + if [[ "$SRC" =~ ^hotfix/ ]]; then echo "✅ hotfix/*"; exit 0; fi + if [[ "$LABELS" =~ cherry-pick|backport ]]; then echo "✅ cherry-pick/backport label"; exit 0; fi + echo "❌ release/* 仅接受 hotfix/* 或带 cherry-pick/backport 标签的 PR"; exit 1 +``` + +> 部署后,需把该 workflow 的 check 名加入各仓 `required_status_checks.contexts`,使其成为合并硬门槛。 +> **状态:workflow 文件尚未部署**(待显式授权推送到 7 仓 main)。 + +--- + +## 5. 分支模型流程图 + +```mermaid +flowchart TD + subgraph DEV["日常开发"] + F["feature/*"] -->|PR + 1 review| M["main
(集成主干 · 最新非最稳)"] + BUG["bugfix/*"] -->|PR + 1 review| M + end + + subgraph RELEASE["发布冻结"] + M -->|切发布分支 + 打 tag| R["release/vX.Y.Z
(稳定发布快照 · 最严保护)"] + end + + subgraph MAINT["发布后维护"] + R -.->|切出| HF["hotfix/*"] + HF -->|PR ✅ 允许| R + FEAT["已验证 feature
(cherry-pick/backport 标签)"] -->|PR ✅ 允许| R + end + + M -.->|❌ 禁止直接合并| R + F -.->|❌ 禁止直接合并| R + + HF -.->|backport 修复回主干| M + + classDef stable fill:#1b5e20,stroke:#fff,color:#fff; + classDef main fill:#0d47a1,stroke:#fff,color:#fff; + classDef work fill:#37474f,stroke:#fff,color:#fff; + class R stable; + class M main; + class F,BUG,HF,FEAT work; +``` + +**关键路径:** +- 正常流:`feature/*` → (PR) → `main` → (冻结+tag) → `release/vX.Y.Z` +- 紧急修复:`release/vX.Y.Z` → `hotfix/*` → (PR) → `release/vX.Y.Z` → (backport) → `main` +- 回填功能:`main` 上已验证 commit → cherry-pick/backport PR(带标签)→ `release/vX.Y.Z` +- 🚫 被拒:`main` / `develop` / `feature/*` 直接 → `release/*` + +--- + +## 6. 当前落地状态(2026-06-28) + +| 仓库 | owner/repo | `release/v1.1.5` 分支+tag | 保护规则 | 来源校验 workflow | +|---|---|---|---|---| +| xworkmate-app | `ai-workspace-lab/xworkmate-app` | ✅ | ✅ 全量 | ⏳ 待部署 | +| xworkmate-bridge | `ai-workspace-lab/xworkmate-bridge` | ✅ | ✅ 全量 | ⏳ 待部署 | +| xworkspace-console | `ai-workspace-lab/xworkspace-console` | ✅ | ✅ 全量 | ⏳ 待部署 | +| openclaw-multi-session-plugins | `ai-workspace-lab/openclaw-multi-session-plugins` | ✅ | ✅ 全量 | ⏳ 待部署 | +| playbooks | `ai-workspace-infra/playbooks` | ✅ | ✅ 全量 | ⏳ 待部署 | +| iac_modules | `ai-workspace-infra/iac_modules` | ✅ | ✅ 全量 | ⏳ 待部署 | +| xworkspace-core-skills | `ai-workspace-lab/xworkspace-core-skills` | ✅ | ✅ 全量 | ⏳ 待部署 | + +> 分支与 tag 同名 `release/v1.1.5`:推送用显式 refspec(`refs/heads/...` + `refs/tags/...`);本地 checkout 用 `git checkout refs/heads/release/v1.1.5` 避免歧义。 +> `iac_modules` remote 已统一为 `git@github.com:ai-workspace-infra/iac_modules.git`。 + +--- + +## 7. 剩余动作 + +1. ~~**部署来源校验 workflow** 到 7 仓 main~~ ✅ 2026-06-28(走 PR + squash 合并)。 +2. ~~backport workflow 到现有 `release/v1.1.5`~~ ✅ 2026-06-28(见 §8 应急流程)。 +3. workflow 首次跑出 check 名后,加入各仓 `required_status_checks.contexts`,使其成为合并硬门槛。 +4. 后续每发新版(`release/vX.Y.Z`):切分支+tag → 跑 §2 一键脚本应用保护。 + +--- + +## 8. 应急流程 — 向严格保护的 `release/v*` 紧急合入 + +**适用场景**:需直接改 `release/v*`(如 backport 门禁 workflow、紧急配置修复),但**当前无可用的第二审阅人**(仅 PR 作者本人账号、code-agent-bot 未就绪等)。 + +> ⚠️ 该流程**临时下调**分支保护,属高风险操作。务必:① 单仓串行、窗口最小化;② 完成立即恢复;③ 记录操作前后保护状态;④ 仅用于 hotfix/backport 类小改,**禁止用于功能合并**。 + +### 标准步骤(每仓) + +```bash +TOKEN=$(gh auth token); SLUG=; PR=; BR=release/v1.1.5 + +# 严保护 payload,仅 required_approving_review_count 变量化 +protect() { # $1 = review_count + curl -s -o /dev/null -w "%{http_code}" -X PUT \ + -H "Authorization: Bearer $TOKEN" -H "Accept: application/vnd.github.v3+json" \ + -d "{\"enforce_admins\":true,\"required_pull_request_reviews\":{\"required_approving_review_count\":$1,\"dismiss_stale_reviews\":true},\"required_status_checks\":{\"strict\":true,\"contexts\":[]},\"required_conversation_resolution\":true,\"required_linear_history\":true,\"restrictions\":null,\"allow_force_pushes\":false,\"allow_deletions\":false}" \ + "https://api.github.com/repos/$SLUG/branches/$(printf %s "$BR" | sed 's#/#%2F#g')/protection" +} + +# 1) 先建 hotfix 分支 + PR(不需改保护) +git switch -c hotfix/ origin/$BR # 改动 & push & gh pr create --base $BR + +# 2) 临时降审阅到 0(窗口开始) +protect 0 + +# 3) squash 合并(linear history 要求:必须 squash/rebase,不能 merge commit) +gh pr merge "$PR" --repo "$SLUG" --squash --delete-branch + +# 4) 立即恢复审阅到 1(窗口结束) +protect 1 +``` + +### 关键约束 +- **不要动 `enforce_admins`**:保持 `true`,仅改 review count。 +- **必须 squash/rebase 合并**:`required_linear_history: true` 禁 merge commit。 +- **status checks 仍 strict**:`contexts: []` 时无强制 check,不阻塞;一旦把 check 名加入 contexts,应急合并前需确保该 PR 的 check 已通过。 +- **验证三件套**:PR `MERGED` + 目标文件存在于分支 + 保护 `review=1` 已恢复。 + +```bash +gh pr view "$PR" --repo "$SLUG" --json state --jq '.state' # → MERGED +curl -s -H "Authorization: Bearer $TOKEN" "https://api.github.com/repos/$SLUG/contents/?ref=$BR" | jq -r '.path // .message' +curl -s -H "Authorization: Bearer $TOKEN" "https://api.github.com/repos/$SLUG/branches/${BR/\//%2F}/protection" | jq '.required_pull_request_reviews.required_approving_review_count' # → 1 +``` + +> **首选正规路径**:有第二审阅人时走 `hotfix/* → PR → 他人 approve → squash 合并`,无需动保护。应急流程仅在审阅人缺位且变更紧迫时使用。 +> +> **首次执行记录(2026-06-28)**:backport `validate-release-pr.yml` 到 7 仓 `release/v1.1.5`,PR `app#21 / bridge#12 / console#3 / plugins#3 / playbooks#20 / iac#213 / core-skills#4`,全部 MERGED,保护已恢复 `review=1`。