Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Use when deploy-engineer is about to deploy the merged-to-main code to the isolated local UAT stack (after code review + SIT Audit pass and merge, before qa-engineer runs E2E/UAT). Provides the applicability gate, pre-flight checks, isolated compose bring-up (independent project name + port offset +900), in-container migration, real-output smoke test, hand-off, and the deploy-report skeleton. Pairs with deployment.md "UAT 环境部署" contract and slash /agf-deploy-uat.
.claude/skills/pcliangx-agf-deploying-uat/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-21 | ✗→✓ | ▲ Improved | 154% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 72% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 1242% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 147% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 93% | 0% |
把合并到 main 后的干净代码部署到与所有 dev worktree 物理隔离的本地 UAT 栈,冒烟自检通过后交接 qa-engineer。本 skill 是 deploy-engineer 的分步 runbook;隔离契约的单一来源是 deployment.md "UAT 环境部署" 节。
满足以下全部才进入部署:
deploy-engineer(review-only / deploy-only,不修源码)。/agf-deploy-uat 手动触发)。任一不满足 → 不部署,SendMessage product-lead 说明缺什么。
git status 无未提交改动,记录待部署 commit SHA(git rev-parse --short HEAD)。绝不部署任何未合并的 dev worktree 分支。docker compose version 正常返回(daemon 在跑)。.env.uat 存在:UAT 专用环境变量文件(含密钥)已就位且 gitignore(不入库)。缺失 → 阻断,请 product-lead 协调补齐。lsof -i:8900 等快速核对),确认不与 dev(base)/ QA pool(base+100..+700)/ 既有 UAT 栈撞车。任一不勾 → 不起栈,先 SendMessage product-lead 解决先决条件。
bashexport COMPOSE_PROJECT_NAME=${APP_NAME}-uat # 独立 project → 容器/网络/卷全独立于 dev / QA export UAT_PORT_OFFSET=900 # → POSTGRES 6332 / BACKEND 8900 / FRONTEND(caddy) 8980 docker compose -p "$COMPOSE_PROJECT_NAME" --env-file .env.uat up -d --build
-p "$COMPOSE_PROJECT_NAME":让容器 / 网络 / 卷全部带 <app>-uat 前缀,与 dev worktree 物理隔离。--env-file .env.uat:注入 UAT 专用变量(DB 连接、LLM key、端口偏移消费等)。--build:必须重建 image(禁止仅 restart——restart 不重建 image,合并后的新代码不会进容器,正是 deployment.md "P0/P1 修复 Close 前的强制门" 节 Step 1「容器重建」记录的失败模式)。docker compose -p "$COMPOSE_PROJECT_NAME" ps 确认各服务 Up(healthy)。DB schema 迁移必须在容器内对 UAT 库跑,不在宿主机:
bashdocker compose -p "$COMPOSE_PROJECT_NAME" exec backend alembic upgrade head
Running upgrade ... 行),贴进部署报告"迁移结果"段。.env.uat / 连接配置问题 → 自修重跑;若是 migration 脚本本身错(代码问题)→ 退回 product-lead → dev。复用 deployment.md "P0/P1 修复 Close 前的强制门" 节 Step 2「curl 实证 AC 边界(真实输出,非 dry-run)」的实证原则——只接受真实响应,拒绝 "dry-run pass" / "本地 unit 已过" / "代码看着对"。
bash curl -sS -w "\nHTTP %{http_code}\n" http://localhost:8900/health curl -sS -w "\nHTTP %{http_code}\n" http://localhost:8900/api/<核心只读端点>
bash curl -sS -I http://localhost:8980 # 期望 200 / index.html 可达
bash docker compose -p "$COMPOSE_PROJECT_NAME" exec postgres psql -U <user> -d <db> -c "\dt"
❌ 部署失败。冒烟范围说明:冒烟只证明"环境立起来、链路通",不是 E2E——不替业务流程 / AC 验收做判断(那是 qa-engineer 的事)。冒烟若暴露代码层缺陷(如核心 API 500),采集证据后退回 product-lead,不自己改源码。
部署门只有两态,不发明新 verdict 词表:
✅ 部署成功(冒烟通过) —— 前置全过 + 起栈 healthy + 迁移成功 + 冒烟真实 200/连通。❌ 部署失败 —— 任一环节失败;报告里标明是环境/配置问题(deploy-engineer 自修重部)还是代码问题(退回 PL → dev)。报告落盘后立即(不等用户问)SendMessage product-lead:
http://localhost:8980 / http://localhost:8900)+ 部署 commit SHA,供 PL 触发 qa-engineer 对共享 UAT 栈跑 E2E。SendMessage({to: "product-lead", message: "UAT 部署完成: [功能名]\n报告: docs/deploy/[feature]-uat-[YYYY-MM-DD].md\nUAT 栈: FRONTEND http://localhost:8980 / BACKEND http://localhost:8900\n部署 commit: [SHA]\n结果: ✅ 部署成功(冒烟通过) / ❌ 部署失败", summary: "UAT 部署: [功能名]"})落到 docs/deploy/<feature>-uat-<YYYY-MM-DD>.md(与 docs/reviews / docs/qa 对称;pool=1,无 agf-matrix.sh 用的 YAML frontmatter):
`markdown# UAT 部署报告 — [Feature] - **Date**: YYYY-MM-DD - **Deployer**: deploy-engineer ([model name]) - **部署 commit (merged main)**: [short SHA] - **Compose project**: ${APP_NAME}-uat - **端口偏移**: UAT_PORT_OFFSET=900 ## UAT 栈服务地址(交给 qa-engineer 作测试目标) | 服务 | URL / 端口 | |---|---| | Frontend (caddy) | http://localhost:8980 | | Backend (API) | http://localhost:8900 | | Postgres | localhost:6332 | ## 前置检查 - [x] main 干净且最新(commit [SHA]) - [x] docker 可用(`docker compose version`) - [x] `.env.uat` 存在(gitignore,未入库) - [x] +900 端口带空闲,不与 dev / QA pool 撞车 ## 隔离起栈
docker compose -p ${APP_NAME}-uat --env-file .env.uat up -d --build
(贴 `docker compose ps` 各服务 Up/healthy 输出)
## 迁移结果(容器内)
docker compose -p ${APP_NAME}-uat exec backend alembic upgrade head (贴真实迁移输出:Running upgrade ... → <revision>)
## 冒烟证据(真实输出,非 dry-run)
- **Frontend 可达**:`curl -I http://localhost:8980` → (贴 HTTP 200 头)
- **Backend 健康**:`curl -w "HTTP %{http_code}" http://localhost:8900/health` → (贴状态码 + body)
- **核心 API**:`curl ... http://localhost:8900/api/<端点>` → (贴真实响应)
- **DB 连通**:`... psql -c "\dt"` → (贴表清单)
## Deploy Gate
**Verdict**: ✅ 部署成功(冒烟通过) / ❌ 部署失败
(失败时:问题归类 = 环境/配置(自修重部) / 代码(退回 product-lead → dev)+ 证据)
## Hand-off
✅ → SendMessage product-lead(附 UAT URL)→ PL 触发 qa-engineer E2E
❌ → SendMessage product-lead(附失败定位)→ PL 决策重部 / 退回 dev-p ${APP_NAME}-uat + 端口偏移 +900(未复用 dev / QA 栈)?任一不行 → 不要声明部署成功,回去补。
docker compose restart 不 --build —— 新代码不进容器(deployment.md "P0/P1 修复 Close 前的强制门" 节 Step 1「容器重建」失败模式)。backend/ / frontend/ —— 越界;采证退回 PL → dev。| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-21 | fail→pass | 10,704 | 8,256 | -23% | 1 | 1 | 0% | 1,598 | 4,052 | +154% | 0 | 0 | — |
case-01 | fail→fail | 4,996 | 7,450 | +49% | 1 | 1 | 0% | 304 | 3,041 | +900% | 0 | 0 | — |
case-02 | fail→fail | 5,480 | 7,989 | +46% | 1 | 1 | 0% | 296 | 3,095 | +946% | 0 | 0 | — |
case-03 | fail→fail | 4,661 | 7,808 | +68% | 1 | 1 | 0% | 212 | 3,241 | +1429% | 0 | 0 | — |
case-04 | fail→pass | 14,897 | 9,626 | -35% | 1 | 1 | 0% | 2,467 | 4,255 | +72% | 0 | 0 | — |
case-05 | fail→pass | 6,776 | 9,554 | +41% | 1 | 1 | 0% | 321 | 4,307 | +1242% | 0 | 0 | — |
case-06 | fail→fail | 5,932 | 8,521 | +44% | 1 | 1 | 0% | 923 | 3,302 | +258% | 0 | 0 | — |
case-07 | fail→pass | 9,022 | 5,714 | -37% | 1 | 1 | 0% | 1,498 | 3,699 | +147% | 0 | 0 | — |
case-08 | fail→pass | 11,960 | 6,090 | -49% | 1 | 1 | 0% | 1,948 | 3,757 | +93% | 0 | 0 | — |
case-09 | fail→pass | 14,749 | 5,141 | -65% | 1 | 1 | 0% | 2,183 | 3,506 | +61% | 0 | 0 | — |
case-10 | fail→pass | 8,956 | 7,262 | -19% | 1 | 1 | 0% | 1,405 | 3,778 | +169% | 0 | 0 | — |
case-11 | pass→pass | 13,256 | 5,488 | -59% | 1 | 1 | 0% | 2,046 | 3,609 | +76% | 0 | 0 | — |
case-12 | fail→pass | 8,510 | 5,773 | -32% | 1 | 1 | 0% | 1,330 | 3,569 | +168% | 0 | 0 | — |
case-13 | fail→pass | 11,108 | 6,533 | -41% | 1 | 1 | 0% | 1,825 | 3,638 | +99% | 0 | 0 | — |
case-14 | fail→pass | 8,194 | 3,160 | -61% | 1 | 1 | 0% | 1,319 | 3,242 | +146% | 0 | 0 | — |
case-15 | fail→pass | 11,905 | 5,394 | -55% | 1 | 1 | 0% | 1,713 | 3,505 | +105% | 0 | 0 | — |
case-16 | fail→fail | 15,736 | 4,831 | -69% | 1 | 1 | 0% | 2,651 | 3,422 | +29% | 0 | 0 | — |
case-17 | pass→pass | 5,834 | 2,751 | -53% | 1 | 1 | 0% | 931 | 3,041 | +227% | 0 | 0 | — |
case-18 | fail→pass | 10,904 | 3,186 | -71% | 1 | 1 | 0% | 1,848 | 3,120 | +69% | 0 | 0 | — |
case-19 | fail→pass | 9,797 | 4,900 | -50% | 1 | 1 | 0% | 1,499 | 3,501 | +134% | 0 | 0 | — |
case-20 | pass→pass | 8,538 | 6,008 | -30% | 1 | 1 | 0% | 1,342 | 3,721 | +177% | 0 | 0 | — |
case-22 | fail→pass | 10,729 | 2,853 | -73% | 1 | 1 | 0% | 1,893 | 3,146 | +66% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 17 counted toward the lift figure. The other 5 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +64 percentage points is the difference between those two pass rates over the 17 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.