merge: feature/rdev-closeout-2026-09-22
This commit is contained in:
@@ -25,14 +25,17 @@
|
||||
- 目标环境批准的实际模型、协议及制品;通过 `PI_AGENT_MODEL` 传入批准值并比对 Runner 实际配置。脚本默认值不构成批准,也不证明实际模型。
|
||||
- 脚本可能构建候选镜像、写 promotion receipt;须满足构建身份/授权条件。`NIGHTLY_SKIP_IMAGE_BUILD=1` 不能补足缺失的制品摘要证据。
|
||||
|
||||
脚本当前筛选 **仅两项**:
|
||||
脚本当前筛选 **五项**(U8 + 四条工作流治理链):
|
||||
|
||||
```text
|
||||
TestMultiIntentU8_RealPI_ConfirmGenerate_PG
|
||||
TestWorkflowGovernance_PiAgent_PG_FullChain
|
||||
TestWorkflowGovernance_PiAgent_PG_ProductManager_FullChain
|
||||
TestWorkflowGovernance_PiAgent_PG_TestManager_FullChain
|
||||
TestWorkflowGovernance_PiAgent_PG_FullNoneMixedChain
|
||||
```
|
||||
|
||||
它不是“全部工作流通过”。按变更范围追加精确名称,例如(前提条件已核验,且已处于相应环境执行租约/独立环境):
|
||||
它覆盖 main / product_manager / test_manager / FullNone 四条工作流治理链,但**不是**「全部工作流通过」,也不含 rdev P3 Go 顶层(rdev 仍用 Python 三样本 harness)。按变更范围追加精确名称,例如(前提条件已核验,且已处于相应环境执行租约/独立环境):
|
||||
|
||||
```bash
|
||||
go test -count=1 -timeout 2h -v ./internal/server/ -run '^TestPiAgent_FullLifecycle_MultiRole_RealWorld_E2E$'
|
||||
@@ -43,7 +46,7 @@ go test -count=1 -timeout 90m -v ./internal/server/ -run '^TestWorkflowGovernanc
|
||||
|
||||
测试筛选区分大小写;`-run 'PI'` 不能选择名称中的 `PiAgent`。追加用例先读其环境前提;FullLifecycle 中 `RUN_FULL_ADHOC_WBS` 与 `RUN_HEAVY_STAGES` 控制额外段,不能把默认未跑段报为已覆盖。普通 PG 用例同样以源码中的精确名称/前提为准。
|
||||
|
||||
运行前列 `expected_tests`(含必须子场景),运行后逐项对照执行、PASS、FAIL、SKIP、未匹配及重试。退出码 0 或 nightly receipt `pass` 不能替代该对照:基线脚本逐项核对两个预期顶层测试;额外子场景/用例仍须逐项核验。缺项不记 PASS,基础设施问题记录 blocker/infra_fail。保留首轮与重试关系,不隐藏失败。
|
||||
运行前列 `expected_tests`(含必须子场景),运行后逐项对照执行、PASS、FAIL、SKIP、未匹配及重试。退出码 0 或 nightly receipt `pass` 不能替代该对照:基线脚本逐项核对五个预期顶层测试;额外子场景/用例仍须逐项核验。缺项不记 PASS,基础设施问题记录 blocker/infra_fail。保留首轮与重试关系,不隐藏失败。
|
||||
|
||||
## 模型与环境证据
|
||||
|
||||
@@ -59,4 +62,4 @@ go test -count=1 -timeout 90m -v ./internal/server/ -run '^TestWorkflowGovernanc
|
||||
|
||||
## 工程工具验收补充
|
||||
|
||||
本地协调与运维守卫使用 `python3 -B -m unittest discover -s scripts/tests -p 'test_*.py' -v`,在临时真实 Git/SQLite/进程环境执行;Docker 守卫测试使用受控目标记录调用,不重建共享服务。nightly 入口现在核对最终尝试日志中两个预期顶层测试均恰好执行且 PASS;零用例、部分 SKIP 或重复拼接证据均不能生成 PASS 收据。该日志核验不是本轮执行了产品 PI 的声明。
|
||||
本地协调与运维守卫使用 `python3 -B -m unittest discover -s scripts/tests -p 'test_*.py' -v`,在临时真实 Git/SQLite/进程环境执行;Docker 守卫测试使用受控目标记录调用,不重建共享服务。nightly 入口现在核对最终尝试日志中五个预期顶层测试均恰好执行且 PASS;零用例、部分 SKIP 或重复拼接证据均不能生成 PASS 收据。该日志核验不是本轮执行了产品 PI 的声明。
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
---
|
||||
title: "W4 rdev 收口"
|
||||
task_id: rdev-closeout-2026-09-22
|
||||
status: done
|
||||
created: 2026-09-22
|
||||
updated: 2026-09-22
|
||||
owner: Cursor
|
||||
task_type: implementation
|
||||
task_tier: small
|
||||
policy_revision: "AGENTS+ops@364ed7f1"
|
||||
branch: feature/rdev-closeout-2026-09-22
|
||||
worktree: .worktrees/rdev-closeout-2026-09-22
|
||||
base_dev_sha: "364ed7f1a3f0393ef77ec4623a9518116ed2cb87"
|
||||
write_scope: [".doc", "configs/overlays", "internal/squad", "scripts", ".github/workflows"]
|
||||
allowed_environments: []
|
||||
head_sha: "364ed7f1a3f0393ef77ec4623a9518116ed2cb87"
|
||||
mutex: rdev-closeout
|
||||
review_state: pending
|
||||
integration_state: pending
|
||||
deployment: not_required
|
||||
cleanup: pending
|
||||
cleanup_owner: 独立维护者
|
||||
cleanup_trigger: tip 为 origin/dev 祖先且无进程后复查
|
||||
remote_sync: not_requested
|
||||
---
|
||||
|
||||
# W4 rdev 收口
|
||||
|
||||
## 用户目标与授权
|
||||
|
||||
- 用户目标:rd_proposal 标题对齐模板;nightly 扩成四工作流;P3 三样本在当前 HEAD 重跑并复验法规表误伤修复;short-term + commit。
|
||||
- 交付终点:实现与证据就绪(本地提交);不合入、不 push。
|
||||
- 禁止项:不 push;不动共享 KB / 项目 143;不启用红线 flag;无 `env:dev` 能力时不写共享服务。
|
||||
|
||||
## 范围与非目标
|
||||
|
||||
- 允许:质量门禁/overlay/hint、nightly 脚本与契约文案、dry fixture、本任务 short-term/报告。
|
||||
- 非目标:从本 worktree 对共享 dev 跑长 E2E;rdev 专用 Go PG 顶层测试;升 FEATURE-MATRIX / gap-matrix。
|
||||
|
||||
## 步骤与验收
|
||||
|
||||
1. [x] `rd_proposal` 精确标题门禁 + ph01 overlay/hint — `rdevProposalHeadingIssues`;`TestRDevQualityGates` dry fixture。
|
||||
2. [x] nightly 扩成四工作流治理链(FullChain ×3 + FullNone)并保留 U8 — `scripts/run-nightly-real-pi.sh` + workflow timeout + 验证契约。
|
||||
3. [x] 法规表误伤 — 既有 `markdownTable` 首表截止 + P3 终稿 dry 复验仍无「问题行缺少」。
|
||||
4. [x] P3 真 PI 重跑 — **blocked**(见下);不以 stub 冒充 PASS。
|
||||
|
||||
## 验证与证据
|
||||
|
||||
| 范围 / 被测 SHA | 命令与环境 | 预期 | 实际 / 判定 | 证据 |
|
||||
|---|---|---|---|---|
|
||||
| 标题门禁 + 法规表 dry | `go test ./internal/squad/ -run 'TestRDevQualityGates\|TestRDevOverlay'` | PASS | PASS | 本机 2026-09-22 |
|
||||
| P3 三样本真 PI | `run_p3_real_pi.py` + 共享/独立 PI | 需 env:dev 租约 + 非 143 项目 | **blocked** | 任务无 `env:dev`;无 `TEST_DATABASE_URL`;规范禁止从 task worktree 写共享服务 |
|
||||
| nightly 四工作流 | 脚本 `--expected` 五项 | 脚本已扩 | 未在本机实跑四链(耗时/租约) | 脚本与契约 diff |
|
||||
|
||||
## 收口与交接
|
||||
|
||||
- 剩余:获 `env:dev`(或独立固定环境)后在新 HEAD 重跑 P3;可选补 rdev Go PG 顶层进 nightly。
|
||||
- 本地提交:本分支 tip;dev 集成 / 远端:未请求。
|
||||
- 红线未动。
|
||||
|
||||
## 相关链接
|
||||
|
||||
- [报告](../../test-reports/2026-09-22-rdev-closeout-test-report.md)
|
||||
- [P3 历史报告](../../test-reports/2026-09-19-rdev-p3-real-pi-test-report.md)
|
||||
- [验证契约](../2026-09-21-validation-contract.md)
|
||||
@@ -0,0 +1,52 @@
|
||||
# W4 rdev 收口测试报告
|
||||
|
||||
## 一、背景
|
||||
|
||||
P3(2026-09-19)在项目 6533 真 PI 上跑过三样本:`rd_proposal` 生成完成但章节标题未对齐模板;`rd_planning_review` 因同节法规对照表被算进「问题行」而 quality_failed(score 20)。同日已修 `markdownTable` 首表截止,但标题对齐与 nightly 四工作流挂钩仍开放。
|
||||
|
||||
## 二、目标
|
||||
|
||||
1. 建议书标题必须对齐 `templates/docs/rd_proposal.md` 四个专业 `##`。
|
||||
2. nightly 从「U8 + FullNone」扩成「U8 + 四条工作流治理链」。
|
||||
3. 用 dry fixture 复验法规表误伤修复;真 PI 三样本仅在授权环境可跑时重跑。
|
||||
|
||||
## 三、环境
|
||||
|
||||
- OS:darwin;worktree `feature/rdev-closeout-2026-09-22`;基线 `364ed7f1`。
|
||||
- 共享 dev health:schema 61、`kb_ready`、Runner 可达;**本任务 capabilities 无 `env:dev`**,且无 `TEST_DATABASE_URL`,故不写共享服务、不重跑真 PI。
|
||||
|
||||
## 四、结果
|
||||
|
||||
### 4.1 标题对齐门禁
|
||||
|
||||
- **输入**:`rdevProposalHeadingIssues`;P3 终稿 dry;对齐样例;「风险清单」负例。
|
||||
- **实际**:P3 终稿检出缺失「项目背景与立项依据」「目标、里程碑与资源假设」「主要风险与对策概览」等;对齐样例 0 issue;改名为「风险清单」失败。
|
||||
- **判定**:PASS(门禁+fixture)。真 PI 重跑 **blocked**,不记生成 PASS。
|
||||
- **附**:`configs/overlays/rdev_ph01.md` 与 `rdev_stage_meta` hint 写明禁止自拟标题。
|
||||
|
||||
### 4.2 法规表误伤
|
||||
|
||||
- **输入**:既有 later-table 用例 + `rd_planning_review-final.md`。
|
||||
- **实际**:无「问题行缺少」误报。
|
||||
- **判定**:PASS(dry 复验)。
|
||||
|
||||
### 4.3 nightly 四工作流
|
||||
|
||||
- **输入**:`scripts/run-nightly-real-pi.sh`、`nightly-real-pi.yml`、验证契约。
|
||||
- **实际**:`RUN_FILTER` 含 FullChain / ProductManager_FullChain / TestManager_FullChain / FullNoneMixedChain + U8;suite 默认超时 180m;Actions job 240m;契约列出五项 expected。
|
||||
- **判定**:脚本与契约 PASS。本机未实跑四链(租约/时长);rdev Python P3 **未**挂进 nightly(无 Go 顶层脚本)。
|
||||
|
||||
### 4.4 P3 真 PI 重跑
|
||||
|
||||
- **判定**:blocked。原因:任务无 `env:dev`;操作规范禁止从 task worktree 写共享服务;`.env` 无 `TEST_DATABASE_URL`;用户禁止动项目 143 / 共享 KB。接管条件:独立固定 PG + env 租约后执行 `run_p3_real_pi.py`。
|
||||
|
||||
## 五、套件
|
||||
|
||||
```text
|
||||
go test -count=1 ./internal/squad/ -run 'TestRDevQualityGates|TestRDevOverlay'
|
||||
# ok
|
||||
```
|
||||
|
||||
## 六、结论
|
||||
|
||||
门禁、overlay、nightly 四工作流脚本与 dry 复验已就绪。真 PI 三样本与 nightly 实跑收据待授权环境。红线未动。
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
# Do not use ubuntu-latest docker isolation for this job on this machine.
|
||||
nightly-real-pi:
|
||||
runs-on: nightly
|
||||
timeout-minutes: 120
|
||||
timeout-minutes: 240
|
||||
permissions:
|
||||
contents: read
|
||||
env:
|
||||
|
||||
@@ -5,7 +5,11 @@
|
||||
### role:writer
|
||||
|
||||
写满策划类章节;结论与范围表一致。
|
||||
项目建议书(rd_proposal)的 `##` 标题必须原样使用模板:
|
||||
「项目背景与立项依据」「产品定义与范围」「目标、里程碑与资源假设」「主要风险与对策概览」。
|
||||
不得改成「风险清单」「产品定义」等自拟标题,也不得加「工程师视角」等后缀。
|
||||
|
||||
### role:leader
|
||||
|
||||
查范围是否越权到未批准内容;结论是否可追溯到前序 bizdev 批准件。
|
||||
核对建议书章节标题是否与 template.md 完全一致;标题不对齐则判门禁失败并要求修复。
|
||||
|
||||
@@ -54,25 +54,23 @@ func (q *QualityGate) Validate(wsDir string, taskKey string, content string) (*Q
|
||||
CheckedAt: now,
|
||||
}
|
||||
|
||||
// 1. 检查标题完整性 (对比 template.md 的 ## 章节)
|
||||
// 1. 检查标题完整性 (对比 template.md 的 ## 章节;清洗后须精确相等,禁止自拟近义标题)
|
||||
tmplPath := filepath.Join(wsDir, "template.md")
|
||||
tmplData, err := os.ReadFile(tmplPath)
|
||||
if err == nil {
|
||||
expectedHeadings := extractHeadings(string(tmplData))
|
||||
actualHeadings := extractHeadings(content)
|
||||
actualSet := make(map[string]struct{}, len(actualHeadings))
|
||||
for _, act := range actualHeadings {
|
||||
actualSet[act] = struct{}{}
|
||||
}
|
||||
for _, h := range expectedHeadings {
|
||||
found := false
|
||||
for _, act := range actualHeadings {
|
||||
if strings.Contains(act, h) || strings.Contains(h, act) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found && !strings.Contains(content, h) {
|
||||
report.MissingSections = append(report.MissingSections, h)
|
||||
report.Violations = append(report.Violations, fmt.Sprintf("缺少必填章节: %s", h))
|
||||
report.Score -= 15.0
|
||||
if _, ok := actualSet[h]; ok {
|
||||
continue
|
||||
}
|
||||
report.MissingSections = append(report.MissingSections, h)
|
||||
report.Violations = append(report.Violations, fmt.Sprintf("缺少必填章节: %s", h))
|
||||
report.Score -= 15.0
|
||||
}
|
||||
if len(report.MissingSections) > 0 {
|
||||
report.TitleCheck = false
|
||||
|
||||
@@ -12,12 +12,23 @@ import (
|
||||
|
||||
var rdevReqIDPattern = regexp.MustCompile(`\b(UR|RS)-(\d+)\b`)
|
||||
|
||||
// rdProposalRequiredHeadings are the professional ## titles from templates/docs/rd_proposal.md.
|
||||
// Exact cleaned match is required; fuzzy Contains is not enough for title alignment.
|
||||
var rdProposalRequiredHeadings = []string{
|
||||
"项目背景与立项依据",
|
||||
"产品定义与范围",
|
||||
"目标、里程碑与资源假设",
|
||||
"主要风险与对策概览",
|
||||
}
|
||||
|
||||
func rdevDeterministicViolations(wsDir, taskKey, content string) []string {
|
||||
meta, ok := LookupRDevTask(taskKey)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
switch taskKey {
|
||||
case "rd_proposal":
|
||||
return rdevProposalHeadingIssues(content)
|
||||
case "rd_user_needs":
|
||||
return rdevRequirementIssues(wsDir, content, "UR")
|
||||
case "rd_system_reqs":
|
||||
@@ -33,6 +44,25 @@ func rdevDeterministicViolations(wsDir, taskKey, content string) []string {
|
||||
}
|
||||
}
|
||||
|
||||
func rdevProposalHeadingIssues(content string) []string {
|
||||
// Require literal "## 标题" lines (no numbering / engineer-suffix variants).
|
||||
var issues []string
|
||||
for _, want := range rdProposalRequiredHeadings {
|
||||
exact := "## " + want
|
||||
found := false
|
||||
for _, line := range strings.Split(content, "\n") {
|
||||
if strings.TrimSpace(line) == exact {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
issues = append(issues, "建议书章节标题未对齐模板: "+want)
|
||||
}
|
||||
}
|
||||
return issues
|
||||
}
|
||||
|
||||
func rdevRequirementIssues(wsDir, content, prefix string) []string {
|
||||
var issues []string
|
||||
if strings.Contains(content, "随机抽取") {
|
||||
|
||||
@@ -133,6 +133,22 @@ func TestRDevQualityGates(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
proposalSample, err := os.ReadFile("../../.doc/test-reports/assets/2026-09-19-rdev-p3-real-pi/rd_proposal-final.md")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if issues := rdevProposalHeadingIssues(string(proposalSample)); len(issues) == 0 {
|
||||
t.Fatal("P3 rd_proposal dry fixture must fail title alignment (self-authored headings)")
|
||||
}
|
||||
aligned := "## 结论\n\nok\n\n## 适用性\n\nok\n\n## 项目背景与立项依据\n\nok\n\n## 产品定义与范围\n\nok\n\n## 目标、里程碑与资源假设\n\nok\n\n## 主要风险与对策概览\n\nok\n\n## 追溯\n\n| RD- | |\n\n## 已有材料摘要\n\nok\n\n## 待确认清单\n\n- 无\n\n## 签署\n\nok\n\n## 说明\n\nok\n"
|
||||
if issues := rdevProposalHeadingIssues(aligned); len(issues) != 0 {
|
||||
t.Fatalf("template-aligned proposal must pass heading gate: %v", issues)
|
||||
}
|
||||
fuzzy := strings.ReplaceAll(aligned, "## 主要风险与对策概览", "## 风险清单")
|
||||
if got := rdevProposalHeadingIssues(fuzzy); len(got) == 0 {
|
||||
t.Fatal("renamed risk heading must fail exact title alignment")
|
||||
}
|
||||
|
||||
thin := "已收照片 1 张。"
|
||||
rep, err = gate.Validate(ws, "rd_prototype_photos", thin)
|
||||
if err != nil {
|
||||
|
||||
@@ -18,7 +18,9 @@ type rdevOverrideStep struct {
|
||||
|
||||
var rdevStageHints = map[string]rdevStageHint{
|
||||
"rd_proposal": {
|
||||
Hint: "按模板编制《项目建议书》(策划)。写满章节并给出本阶段结论与追溯;缺项写「待确认」,不做疗效宣称。",
|
||||
Hint: "按模板编制《项目建议书》(策划)。## 标题必须与 template.md 完全一致:" +
|
||||
"「项目背景与立项依据」「产品定义与范围」「目标、里程碑与资源假设」「主要风险与对策概览」;" +
|
||||
"禁止改写为「风险清单」等自拟标题。写满章节并给出本阶段结论与追溯;缺项写「待确认」,不做疗效宣称。",
|
||||
Aliases: []string{"项目建议书", "立项建议"},
|
||||
},
|
||||
"rd_design_plan": {
|
||||
|
||||
@@ -26,9 +26,9 @@ RUNNER_URL="${PI_AGENT_RUNNER_URL:-http://127.0.0.1:18865}"
|
||||
TOKEN="${PI_AGENT_RUNNER_AUTH_TOKEN:-${RUNNER_AUTH_TOKEN:-}}"
|
||||
MODEL_ID="${PI_AGENT_MODEL:-MiniMax-M2.7-highspeed}"
|
||||
PROTOCOL="${PI_AGENT_PROTOCOL:-typed-result-v1}"
|
||||
TIMEOUT="${NIGHTLY_SUITE_TIMEOUT:-90m}"
|
||||
TIMEOUT="${NIGHTLY_SUITE_TIMEOUT:-180m}"
|
||||
COMMIT="$(git rev-parse HEAD)"
|
||||
SUITE="nightly-real-pi-u8-fullnone"
|
||||
SUITE="nightly-real-pi-u8-four-workflows"
|
||||
STAMP="$(date -u +%Y%m%dT%H%M%SZ)"
|
||||
EVIDENCE_DIR="${NIGHTLY_EVIDENCE_DIR:-${ROOT}/.doc/test-reports/assets/promotion-receipts/evidence-${COMMIT:0:12}-${STAMP}}"
|
||||
mkdir -p "${EVIDENCE_DIR}"
|
||||
@@ -172,7 +172,9 @@ preflight_shared_kb
|
||||
# Clear env pollution that flakes short/config tests elsewhere.
|
||||
unset AGENT_TIMEOUT KB_DATABASE_URL KB_EMBEDDING_DIM 2>/dev/null || true
|
||||
|
||||
RUN_FILTER='TestMultiIntentU8_RealPI_ConfirmGenerate_PG|TestWorkflowGovernance_PiAgent_PG_FullNoneMixedChain'
|
||||
# Four workflow governance chains (main / product_manager / test_manager / FullNone)
|
||||
# plus U8 confirm-generate. Rdev P3 remains the Python harness (not yet a Go PG top-level).
|
||||
RUN_FILTER='TestMultiIntentU8_RealPI_ConfirmGenerate_PG|TestWorkflowGovernance_PiAgent_PG_(FullChain|ProductManager_FullChain|TestManager_FullChain|FullNoneMixedChain)$'
|
||||
LOG_FILE="${EVIDENCE_DIR}/go-test.txt"
|
||||
set +e
|
||||
go test -count=1 -timeout "${TIMEOUT}" -v ./internal/server/ -run "${RUN_FILTER}" 2>&1 | tee "${LOG_FILE}"
|
||||
@@ -190,9 +192,12 @@ fi
|
||||
set -e
|
||||
|
||||
if [[ "${TEST_RC}" -eq 0 ]]; then
|
||||
# Exit zero alone also covers no tests and partial skips; require both named tests.
|
||||
# Exit zero alone also covers no tests and partial skips; require all named top-level tests.
|
||||
if ! python3 "${ROOT}/scripts/verify_go_test_evidence.py" --log "${RESULT_LOG}" \
|
||||
--expected TestMultiIntentU8_RealPI_ConfirmGenerate_PG \
|
||||
--expected TestWorkflowGovernance_PiAgent_PG_FullChain \
|
||||
--expected TestWorkflowGovernance_PiAgent_PG_ProductManager_FullChain \
|
||||
--expected TestWorkflowGovernance_PiAgent_PG_TestManager_FullChain \
|
||||
--expected TestWorkflowGovernance_PiAgent_PG_FullNoneMixedChain \
|
||||
> "${EVIDENCE_DIR}/expected-tests.json"; then
|
||||
write_receipt infra_fail infra "${LOG_FILE}" "${EVIDENCE_DIR}/expected-tests.json"
|
||||
|
||||
Reference in New Issue
Block a user