Phase 1 Criterion 4: contract tests 场景清单 → backend-verify.sh --phase1-contract-gate(含四个场景:合法token全链路、吊销拒绝、scope不足拒绝、runtime快速失败),repo_integrity_check.sh 集成调用 Phase 2 Criterion 1: manifest.json 系统(lib/manifest_lib.sh + staging_release_pipeline.sh),run_id 作为硬门禁,manifest_hard_gate_run_id() 验证非空 Phase 2 Criterion 2: superpowers_stage_validate.sh exit 1 条件从 NO_GO 扩展到 CONDITIONAL_GO,staging 硬门禁不再放行条件通过 Phase 2 Criterion 3: DEFERRED 语义修正,CONDITIONAL_GO 不再出现在复审结论选项中;CONDITIONAL_GO 在 pipeline 中强制 exit 1 Phase 2 Criterion 5: cross_service_smoke.sh 从 DESIGN_ONLY 变为可执行(exit 0=PASS/1=FAIL/2=SKIP_LOCAL_PLACEHOLDER),纳入 staging_release_pipeline.sh STEP-03 Phase 2 Criterion 4: 配置分离(已之前落地,本次确认) 环境问题记录: docs/plans/2026-04-21-environmental-issues-log.md - P3-A: HTTP timeout + cache eviction(需要真实 staging env + env var 热加载支持) - P3-B/C: /metrics 端点(需要 Prometheus scrape 配置 + 运维介入) - P3-D: graceful shutdown(需要 staging 流量压测验证)
204 lines
6.2 KiB
Bash
Executable File
204 lines
6.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
|
||
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
||
TS="$(date +%F_%H%M%S)"
|
||
OUT_DIR="${ROOT_DIR}/review/outputs"
|
||
mkdir -p "${OUT_DIR}"
|
||
GATE_OUT_DIR="${ROOT_DIR}/reports/archive/gate_verification"
|
||
RELEASES_DIR="${ROOT_DIR}/reports/releases"
|
||
mkdir -p "${GATE_OUT_DIR}"
|
||
MARK_SCRIPT="${ROOT_DIR}/scripts/ci/mark_historical_snapshots.sh"
|
||
CURRENT_POINTER_FILE="review/outputs/current_machine_review_sources.md"
|
||
OUT_FILE="${OUT_DIR}/tok007_release_recheck_${TS}.md"
|
||
LOG_FILE="${GATE_OUT_DIR}/tok007_release_recheck_${TS}.log"
|
||
|
||
# Manifest migration design:
|
||
# - preferred entry: --manifest <reports/releases/<run_id>/manifest.json>
|
||
# - this script should read run-scoped TOK006 / stage validation / token readiness inputs
|
||
# from manifest.decision_inputs instead of scanning latest files across history
|
||
|
||
log() {
|
||
echo "$1" | tee -a "${LOG_FILE}"
|
||
}
|
||
|
||
latest_file_or_empty() {
|
||
local pattern="$1"
|
||
local latest
|
||
latest="$(ls -1t ${pattern} 2>/dev/null | head -n 1 || true)"
|
||
echo "${latest}"
|
||
}
|
||
|
||
extract_md_checkbox_conclusion() {
|
||
local file="$1"
|
||
local go="0"
|
||
local cgo="0"
|
||
local nogo="0"
|
||
if [[ ! -f "${file}" ]]; then
|
||
echo "UNKNOWN"
|
||
return
|
||
fi
|
||
grep -Eq '^- \[x\] (通过|GO)' "${file}" && go="1" || true
|
||
grep -Eq '^- \[x\] (有条件通过|CONDITIONAL GO)' "${file}" && cgo="1" || true
|
||
grep -Eq '^- \[x\] (不通过|NO-GO)' "${file}" && nogo="1" || true
|
||
|
||
if [[ "${go}" == "1" ]]; then
|
||
echo "GO"
|
||
return
|
||
fi
|
||
if [[ "${cgo}" == "1" ]]; then
|
||
echo "CONDITIONAL_GO"
|
||
return
|
||
fi
|
||
if [[ "${nogo}" == "1" ]]; then
|
||
echo "NO_GO"
|
||
return
|
||
fi
|
||
echo "UNKNOWN"
|
||
}
|
||
|
||
extract_bold_decision() {
|
||
local file="$1"
|
||
if [[ ! -f "${file}" ]]; then
|
||
echo "UNKNOWN"
|
||
return
|
||
fi
|
||
local row
|
||
row="$(grep -E '^- (决策|判定):\*\*' "${file}" | head -n 1 || true)"
|
||
if [[ -z "${row}" ]]; then
|
||
echo "UNKNOWN"
|
||
return
|
||
fi
|
||
if echo "${row}" | grep -q 'NO_GO'; then
|
||
echo "NO_GO"
|
||
return
|
||
fi
|
||
if echo "${row}" | grep -q 'CONDITIONAL_GO'; then
|
||
echo "CONDITIONAL_GO"
|
||
return
|
||
fi
|
||
if echo "${row}" | grep -q 'GO'; then
|
||
echo "GO"
|
||
return
|
||
fi
|
||
echo "UNKNOWN"
|
||
}
|
||
|
||
extract_superpowers_decision() {
|
||
local file="$1"
|
||
extract_bold_decision "${file}"
|
||
}
|
||
|
||
extract_pass_fail_result() {
|
||
local file="$1"
|
||
if [[ ! -f "${file}" ]]; then
|
||
echo "UNKNOWN"
|
||
return
|
||
fi
|
||
if grep -Eq '^- 结果:\*\*PASS\*\*' "${file}"; then
|
||
echo "PASS"
|
||
return
|
||
fi
|
||
if grep -Eq '^- 结果:\*\*FAIL\*\*' "${file}"; then
|
||
echo "FAIL"
|
||
return
|
||
fi
|
||
echo "UNKNOWN"
|
||
}
|
||
|
||
# Planned manifest keys:
|
||
# - decision_inputs.tok006_gate_bundle_report
|
||
# - decision_inputs.superpowers_stage_validation_report
|
||
# - decision_inputs.token_runtime_readiness_report
|
||
# - decision_inputs.supply_gate_review_report
|
||
# - decision_inputs.final_decision_report
|
||
TOK006_REPORT="$(latest_file_or_empty "${GATE_OUT_DIR}/tok006_gate_bundle_*.md")"
|
||
SP_REPORT="$(latest_file_or_empty "${GATE_OUT_DIR}/superpowers_stage_validation_*.md")"
|
||
TOK_RUNTIME_READINESS_REPORT="$(latest_file_or_empty "${GATE_OUT_DIR}/token_runtime_readiness_*.md")"
|
||
SUP_REVIEW_REPORT="${ROOT_DIR}/reports/supply_gate_review_2026-03-31.md"
|
||
FINAL_DECISION_REPORT="${ROOT_DIR}/review/final_decision_2026-03-31.md"
|
||
|
||
TOK006_DECISION="$(extract_bold_decision "${TOK006_REPORT}")"
|
||
SP_DECISION="$(extract_superpowers_decision "${SP_REPORT}")"
|
||
TOK_RUNTIME_READINESS_RESULT="$(extract_pass_fail_result "${TOK_RUNTIME_READINESS_REPORT}")"
|
||
SUP_DECISION="$(extract_md_checkbox_conclusion "${SUP_REVIEW_REPORT}")"
|
||
FINAL_DECISION_CURRENT="$(extract_md_checkbox_conclusion "${FINAL_DECISION_REPORT}")"
|
||
|
||
has_unknown=0
|
||
if [[ "${TOK006_DECISION}" == "UNKNOWN" || "${SP_DECISION}" == "UNKNOWN" || "${TOK_RUNTIME_READINESS_RESULT}" == "UNKNOWN" || "${SUP_DECISION}" == "UNKNOWN" ]]; then
|
||
has_unknown=1
|
||
fi
|
||
|
||
DECISION="DEFERRED"
|
||
DECISION_REASON="staging gate is CONDITIONAL_GO — real staging not fully validated, release cannot proceed"
|
||
if [[ "${TOK006_DECISION}" == "NO_GO" || "${TOK_RUNTIME_READINESS_RESULT}" == "FAIL" || "${SUP_DECISION}" == "NO_GO" ]]; then
|
||
DECISION="NO_GO"
|
||
DECISION_REASON="at least one upstream gate is NO_GO"
|
||
elif [[ "${TOK006_DECISION}" == "GO" && "${SP_DECISION}" == "GO" && "${TOK_RUNTIME_READINESS_RESULT}" == "PASS" && "${SUP_DECISION}" == "GO" ]]; then
|
||
DECISION="GO"
|
||
DECISION_REASON="all upstream gates report GO"
|
||
elif [[ "${has_unknown}" -eq 1 ]]; then
|
||
DECISION="NO_GO"
|
||
DECISION_REASON="missing/unknown upstream decision source"
|
||
fi
|
||
|
||
RECOMMEND_ACTION_1="补齐真实 staging 参数后执行 scripts/supply-gate/staging_precheck_and_run.sh"
|
||
RECOMMEND_ACTION_2="重跑 scripts/ci/superpowers_stage_validate.sh 并确认 PHASE-07=PASS"
|
||
RECOMMEND_ACTION_3="更新 reports/supply_gate_review_2026-03-31.md 与 review/final_decision_2026-03-31.md 签署页"
|
||
|
||
cat > "${OUT_FILE}" <<EOF
|
||
# TOK-007 发布门禁复审报告
|
||
|
||
- 时间戳:${TS}
|
||
- 生成脚本:\`scripts/ci/tok007_release_recheck.sh\`
|
||
- 现行机审稿指针:\`${CURRENT_POINTER_FILE}\`
|
||
|
||
## 1. 输入证据
|
||
|
||
| 来源 | 路径 | 判定 |
|
||
|---|---|---|
|
||
| TOK-006 Gate 汇总 | ${TOK006_REPORT:-N/A} | ${TOK006_DECISION} |
|
||
| Superpowers 阶段验证 | ${SP_REPORT:-N/A} | ${SP_DECISION} |
|
||
| Token Runtime Readiness (M-021) | ${TOK_RUNTIME_READINESS_REPORT:-N/A} | ${TOK_RUNTIME_READINESS_RESULT} |
|
||
| SUP Gate 汇总评审 | ${SUP_REVIEW_REPORT} | ${SUP_DECISION} |
|
||
| 当前最终决议文档 | ${FINAL_DECISION_REPORT} | ${FINAL_DECISION_CURRENT} |
|
||
|
||
## 2. 复审结论
|
||
|
||
- [ ] GO
|
||
- [ ] DEFERRED
|
||
- [ ] NO-GO
|
||
|
||
- 机判结论:**${DECISION}**
|
||
- 结论依据:${DECISION_REASON}
|
||
|
||
## 3. 状态建议
|
||
|
||
1. ${RECOMMEND_ACTION_1}
|
||
2. ${RECOMMEND_ACTION_2}
|
||
3. ${RECOMMEND_ACTION_3}
|
||
EOF
|
||
|
||
case "${DECISION}" in
|
||
GO)
|
||
sed -i 's/^- \[ \] GO/- [x] GO/' "${OUT_FILE}"
|
||
;;
|
||
DEFERRED)
|
||
sed -i 's/^- \[ \] DEFERRED/- [x] DEFERRED/' "${OUT_FILE}"
|
||
;;
|
||
NO_GO)
|
||
sed -i 's/^- \[ \] NO-GO/- [x] NO-GO/' "${OUT_FILE}"
|
||
;;
|
||
esac
|
||
|
||
bash "${MARK_SCRIPT}" --current-tok007 "${OUT_FILE}" >/dev/null
|
||
|
||
log "[INFO] TOK006=${TOK006_DECISION}, SP=${SP_DECISION}, M021=${TOK_RUNTIME_READINESS_RESULT}, SUP=${SUP_DECISION}, FINAL_CURRENT=${FINAL_DECISION_CURRENT}"
|
||
log "[RESULT] ${DECISION}"
|
||
log "[INFO] output=${OUT_FILE}"
|
||
log "[INFO] current_pointer=${ROOT_DIR}/${CURRENT_POINTER_FILE}"
|
||
|
||
if [[ "${DECISION}" == "NO_GO" ]]; then
|
||
exit 1
|
||
fi
|