diff --git a/docs/plans/2026-04-21-project-quality-performance-ops-optimization-execution-log.md b/docs/plans/2026-04-21-project-quality-performance-ops-optimization-execution-log.md index 7b7f9b84..f612598b 100644 --- a/docs/plans/2026-04-21-project-quality-performance-ops-optimization-execution-log.md +++ b/docs/plans/2026-04-21-project-quality-performance-ops-optimization-execution-log.md @@ -94,3 +94,22 @@ rg -n "IntrospectTokenResponse|tenant_id|project_id|operator_id|metadata|IssueTo 1. 已创建 `docs/plans/2026-04-21-release-manifest-contract.md`,记录 `latest_file_or_empty` 依赖入口、`run_id` 规则、目录结构与 `manifest.json` 必填字段。 2. 已创建 `reports/releases/.gitkeep`,为后续 `` 工件目录预留稳定路径。 3. 已在四个脚本中补入 manifest 迁移设计说明,明确后续必须从 `decision_inputs` / `artifact_paths` 读取本次 run 的证据。 + +## P2-B 真实 staging 硬门禁规则设计完成 + +执行命令: + +```bash +rg -n 'P2-B-0[1-8]|PASS_REAL|PASS_REHEARSAL|FAIL|override|DEFERRED|real_staging_pass' docs/plans/2026-04-21-real-staging-gate-rules.md +bash -n scripts/ci/superpowers_stage_validate.sh +bash -n scripts/ci/staging_real_readiness_check.sh +bash -n scripts/ci/superpowers_release_pipeline.sh +bash -n scripts/ci/final_decision_consistency_check.sh +git diff --check +``` + +执行结果: + +1. 已创建 `docs/plans/2026-04-21-real-staging-gate-rules.md`,逐项覆盖 `P2-B-01` 到 `P2-B-08`,写死 rehearsal / real staging 术语边界、`PASS_REAL|PASS_REHEARSAL|FAIL` 状态枚举、override 约束和完成率口径。 +2. 已在 `scripts/ci/superpowers_stage_validate.sh`、`scripts/ci/staging_real_readiness_check.sh`、`scripts/ci/superpowers_release_pipeline.sh`、`scripts/ci/final_decision_consistency_check.sh` 补入迁移设计注释,明确真实 staging 是唯一 release 硬门禁,且 `DEFERRED` / rehearsal 不得计入 release pass。 +3. 四个脚本 `bash -n` 通过,且 `git diff --check` 无格式错误;本批次仅落设计规则与迁移约束,没有伪装成已完成实现。 diff --git a/docs/plans/2026-04-21-project-quality-performance-ops-optimization-plan.md b/docs/plans/2026-04-21-project-quality-performance-ops-optimization-plan.md index 7819639f..e6cfac1e 100644 --- a/docs/plans/2026-04-21-project-quality-performance-ops-optimization-plan.md +++ b/docs/plans/2026-04-21-project-quality-performance-ops-optimization-plan.md @@ -329,21 +329,21 @@ - Modify: `scripts/ci/final_decision_consistency_check.sh` - Create: `docs/plans/2026-04-21-real-staging-gate-rules.md` -- [ ] `P2-B-01` 找出 `mock`、`local`、`DEFERRED` 被计为通过的判定点。 +- [x] `P2-B-01` 找出 `mock`、`local`、`DEFERRED` 被计为通过的判定点。 完成标准:每个判定点都有文件和行号。 -- [ ] `P2-B-02` 定义 rehearsal 与 real staging 的术语。 +- [x] `P2-B-02` 定义 rehearsal 与 real staging 的术语。 完成标准:规则文档中两者语义不重叠。 -- [ ] `P2-B-03` 定义“只有 real staging 通过才允许 release pass”的总规则。 +- [x] `P2-B-03` 定义“只有 real staging 通过才允许 release pass”的总规则。 完成标准:总规则写成一句可执行判定语句。 -- [ ] `P2-B-04` 设计 `superpowers_stage_validate.sh` 的状态枚举。 +- [x] `P2-B-04` 设计 `superpowers_stage_validate.sh` 的状态枚举。 完成标准:至少区分 `PASS_REAL`、`PASS_REHEARSAL`、`FAIL`。 -- [ ] `P2-B-05` 设计 `staging_real_readiness_check.sh` 的阻断输出格式。 +- [x] `P2-B-05` 设计 `staging_real_readiness_check.sh` 的阻断输出格式。 完成标准:输出里包含明确的 pass/fail 字段。 -- [ ] `P2-B-06` 设计 `superpowers_release_pipeline.sh` 的 fail-fast 位置。 +- [x] `P2-B-06` 设计 `superpowers_release_pipeline.sh` 的 fail-fast 位置。 完成标准:release 在 real staging 未通过时立即退出。 -- [ ] `P2-B-07` 设计 override 机制。 +- [x] `P2-B-07` 设计 override 机制。 完成标准:override 必须要求审批人、时间戳、run_id、理由。 -- [ ] `P2-B-08` 设计禁止 `DEFERRED` 计入完成率的规则。 +- [x] `P2-B-08` 设计禁止 `DEFERRED` 计入完成率的规则。 完成标准:文档里写出精确计算口径。 ### Task P2-C: 统一环境语义和配置模板 diff --git a/docs/plans/2026-04-21-real-staging-gate-rules.md b/docs/plans/2026-04-21-real-staging-gate-rules.md new file mode 100644 index 00000000..9bee9f75 --- /dev/null +++ b/docs/plans/2026-04-21-real-staging-gate-rules.md @@ -0,0 +1,105 @@ +# 2026-04-21 Real Staging Gate Rules + +## P2-B-01 当前把 `mock` / `local` / `DEFERRED` 计为通过的判定点 + +1. `scripts/ci/superpowers_stage_validate.sh:100` + local/mock 环境直接把 `PHASE-07` 写成 `DEFERRED`。 +2. `scripts/ci/superpowers_stage_validate.sh:110` + `run_step_allow_deferred` 允许真实 staging 前置检查用 `DEFERRED` 退出。 +3. `scripts/ci/superpowers_stage_validate.sh:166` + `PHASE-02` 到 `PHASE-04` 继续在 `.env.local-mock` 上执行 rehearsal 流程。 +4. `scripts/ci/superpowers_stage_validate.sh:233` + 只要存在 `DEFERRED` 就给出 `CONDITIONAL_GO`,没有直接把它判成失败。 +5. `scripts/ci/superpowers_stage_validate.sh:238` + local/mock 环境即使其余步骤都通过,也只降级到 `CONDITIONAL_GO`,仍可能被后续流水继续消费。 +6. `scripts/ci/staging_real_readiness_check.sh:68` + 环境分类同时存在 `local-mock`、`placeholder`、`real-staging`,但输出结果仍是 `READY/BLOCKED`,没有单独的 real-pass 字段。 +7. `scripts/ci/superpowers_release_pipeline.sh:78` + 发布流水当前在 `STEP-01` 之后不会校验“是否 real staging pass”,会继续执行 `STEP-02` 到 `STEP-04`。 +8. `scripts/ci/final_decision_consistency_check.sh:100` + 当前只比较最终决议与机判是否一致,没有把 `DEFERRED` / rehearsal 明确排除在 release pass 之外。 + +## P2-B-02 rehearsal 与 real staging 术语 + +术语定义: + +1. `rehearsal` + 任一使用 `local-mock`、`localhost`、占位 API 地址、占位 token、或无法访问真实 staging 的运行。 +2. `real staging` + 使用真实外网 staging 地址、真实 owner/viewer/admin token,并通过真实连通性检查的运行。 + +约束: + +1. rehearsal 只用于排练脚本链路与产物结构。 +2. real staging 才能产生发布硬门禁证据。 +3. 两者语义完全不重叠,rehearsal 结果不得冒充 real staging。 + +## P2-B-03 总规则 + +只有当同一 `run_id` 下的 real staging 检查通过,且阶段验证状态为 `PASS_REAL`,发布流水才允许输出 `PASS`。 + +## P2-B-04 `superpowers_stage_validate.sh` 状态枚举设计 + +必须只保留三种发布语义状态: + +1. `PASS_REAL` + `PHASE-07` 在真实 staging 上通过。 +2. `PASS_REHEARSAL` + rehearsal 流程通过,但 `PHASE-07` 是 local/mock/deferred。 +3. `FAIL` + 任一必需阶段失败,或真实 staging 要求未满足。 + +映射约束: + +1. 当前 `GO` 只能在未来映射为 `PASS_REAL`。 +2. 当前 `CONDITIONAL_GO` 统一映射为 `PASS_REHEARSAL`。 +3. `DEFERRED` 只能流向 `PASS_REHEARSAL` 或 `FAIL`,不能直接升格。 + +## P2-B-05 `staging_real_readiness_check.sh` 阻断输出格式 + +输出至少包含以下稳定字段: + +- `real_staging_pass=true|false` +- `classification=REAL|REHEARSAL` +- `reason_code=` +- `run_id=` + +阻断规则: + +1. 只要 `real_staging_pass=false`,发布链路必须立即阻断。 +2. `classification=REHEARSAL` 时,无论其余检查如何,都不能视为 real-pass。 + +## P2-B-06 `superpowers_release_pipeline.sh` fail-fast 位置 + +fail-fast 放置点: + +1. `STEP-01` 执行完阶段验证后立即解析其输出。 +2. 若状态不是 `PASS_REAL` 且没有合法 override,立刻 `exit 1`。 +3. `STEP-02` TOK-007、`STEP-03` final consistency、`STEP-04` final decision candidate 都不得在 non-real-pass 条件下继续执行。 + +## P2-B-07 override 机制设计 + +override 必填字段: + +- `approver` +- `timestamp` +- `run_id` +- `reason` + +约束: + +1. override 必须显式落盘到本次 `run_id` 目录。 +2. 没有完整四字段的 override 一律视为无效。 +3. override 只能豁免发布阻断,不能把 rehearsal 改写成 real staging 事实。 + +## P2-B-08 `DEFERRED` 不计入完成率的规则 + +精确口径: + +`phase_completion_rate = PASS_REAL_required_phases / total_required_phases` + +规则说明: + +1. 分子只统计 `PASS_REAL` 的必需阶段。 +2. `DEFERRED`、`PASS_REHEARSAL`、`WARN`、`SKIP` 都不计入分子。 +3. `DEFERRED` 仍占据必需阶段名额,因此会拉低完成率,不能被当作“完成一半”或“条件通过”。 diff --git a/scripts/ci/final_decision_consistency_check.sh b/scripts/ci/final_decision_consistency_check.sh index 9351eb41..19ebaf49 100755 --- a/scripts/ci/final_decision_consistency_check.sh +++ b/scripts/ci/final_decision_consistency_check.sh @@ -14,6 +14,10 @@ LOG_FILE="${OUT_DIR}/final_decision_consistency_${TS}.log" # - preferred entry: --manifest /manifest.json> # - this script should bind final_decision, tok007_recheck and stage validation inputs # to one run_id and stop reading historical "latest" outputs +# Real staging gate design: +# - DEFERRED / PASS_REHEARSAL must not be counted as release completion +# - override metadata, if present, must include approver, timestamp, run_id, and reason +# - final consistency WARN must not upgrade a non-real staging run into release PASS latest_file_or_empty() { local pattern="$1" diff --git a/scripts/ci/staging_real_readiness_check.sh b/scripts/ci/staging_real_readiness_check.sh index 5f7a7d21..070e5741 100755 --- a/scripts/ci/staging_real_readiness_check.sh +++ b/scripts/ci/staging_real_readiness_check.sh @@ -15,6 +15,12 @@ TS="$(date +%F_%H%M%S)" REPORT_FILE="${OUT_DIR}/staging_real_readiness_${TS}.md" LOG_FILE="${OUT_DIR}/staging_real_readiness_${TS}.log" +# Planned blocking output contract: +# - real_staging_pass=true|false +# - classification=REAL|REHEARSAL +# - reason_code= +# - run_id= + CHECK_IDS=() CHECK_STATUS=() CHECK_DESC=() @@ -164,6 +170,11 @@ if [[ "${has_fail}" == "1" ]]; then NOTE="at least one required check failed" fi +# Future status mapping: +# - READY => PASS_REAL only when ENV_CLASS=real-staging +# - BLOCKED => FAIL +# - local-mock / placeholder classifications must never be treated as PASS_REAL + { echo "# 真实 STG 就绪度检查" echo diff --git a/scripts/ci/superpowers_release_pipeline.sh b/scripts/ci/superpowers_release_pipeline.sh index 9ffffa56..717c48d8 100755 --- a/scripts/ci/superpowers_release_pipeline.sh +++ b/scripts/ci/superpowers_release_pipeline.sh @@ -13,6 +13,11 @@ ENABLE_MINIMAX_MONITORING="${ENABLE_MINIMAX_MONITORING:-0}" MINIMAX_ENV_FILE="${MINIMAX_ENV_FILE:-scripts/supply-gate/.env.minimax-dev}" MINIMAX_RUN_ACTIVE_SMOKE="${MINIMAX_RUN_ACTIVE_SMOKE:-0}" +# Planned real-staging hard gate: +# - fail fast immediately after STEP-01 if stage validation is not PASS_REAL +# - STEP-02 onward must not run release-path decisions on PASS_REHEARSAL/DEFERRED +# - override, if ever allowed, must require approver, timestamp, run_id, and reason + log() { echo "$1" | tee -a "${LOG_FILE}" } @@ -101,6 +106,10 @@ run_optional_step_non_blocking \ "${ENABLE_MINIMAX_MONITORING}" \ "cd \"${ROOT_DIR}\" && RUN_ACTIVE_SMOKE=\"${MINIMAX_RUN_ACTIVE_SMOKE}\" bash \"scripts/ci/minimax_upstream_daily_snapshot.sh\" \"${TODAY_TAG}\" \"${MINIMAX_ENV_FILE}\" && bash \"scripts/ci/minimax_upstream_trend_report.sh\" \"${TODAY_TAG}\"" +# Planned fail-fast insertion point: +# - parse STEP-01 report here +# - if real staging status != PASS_REAL and no valid override record exists, exit 1 before STEP-02 + has_fail=0 for row in "${STEP_RESULTS[@]}"; do status="$(echo "${row}" | awk -F'|' '{print $2}')" diff --git a/scripts/ci/superpowers_stage_validate.sh b/scripts/ci/superpowers_stage_validate.sh index e2326668..77455579 100755 --- a/scripts/ci/superpowers_stage_validate.sh +++ b/scripts/ci/superpowers_stage_validate.sh @@ -115,6 +115,12 @@ run_phase07() { "env_class=local-mock|placeholder token detected|placeholder API_BASE_URL|missing env var|API_BASE_URL unreachable" } +# Real staging decision design: +# - PASS_REAL: PHASE-07 runs against real staging and succeeds. +# - PASS_REHEARSAL: all executable rehearsal phases pass, but PHASE-07 is local/mock/deferred. +# - FAIL: any required phase fails, or PHASE-07 is not real-pass when release flow requests hard gate. +# - DEFERRED must never be promoted to PASS_REAL. + ensure_mock_server() { if curl -sS -m 2 "http://127.0.0.1:18080/actuator/health" >/dev/null 2>&1; then echo "already_running" @@ -240,6 +246,11 @@ if is_mock_staging_env "${STAGING_ENV_FILE}" && [[ "${DECISION}" == "GO" ]]; the DECISION_REASON="all phases passed but PHASE-07 used local/mock staging env" fi +# Future release hard-gate mapping: +# - GO maps to PASS_REAL only when PHASE-07 is real-staging PASS. +# - CONDITIONAL_GO maps to PASS_REHEARSAL and must not satisfy release pass. +# - NO_GO maps to FAIL. + { echo "# Superpowers 阶段验证报告" echo