docs(ci): define release manifest contract
Add the run_id and manifest contract doc, reserve the reports/releases tree, record the decision in the execution log, and annotate the four release scripts with their planned manifest-based inputs.
This commit is contained in:
@@ -86,3 +86,11 @@ rg -n "IntrospectTokenResponse|tenant_id|project_id|operator_id|metadata|IssueTo
|
||||
1. 已创建 `tests/contract/README.md` 与 `tests/contract/gateway_token_runtime_supply_chain.md`,明确当前 CI 覆盖缺口与四个最小 contract 场景。
|
||||
2. 已创建 `docs/plans/2026-04-21-phase1-contract-gate-checklist.md`,把 Phase 1 关闭条件绑定到 contract gate。
|
||||
3. 已在 `scripts/ci/backend-verify.sh` 和 `scripts/ci/repo_integrity_check.sh` 写明 contract gate 执行位、产物路径和失败语义。
|
||||
|
||||
## P2-A release manifest 合同设计完成
|
||||
|
||||
执行结果:
|
||||
|
||||
1. 已创建 `docs/plans/2026-04-21-release-manifest-contract.md`,记录 `latest_file_or_empty` 依赖入口、`run_id` 规则、目录结构与 `manifest.json` 必填字段。
|
||||
2. 已创建 `reports/releases/.gitkeep`,为后续 `<run_id>` 工件目录预留稳定路径。
|
||||
3. 已在四个脚本中补入 manifest 迁移设计说明,明确后续必须从 `decision_inputs` / `artifact_paths` 读取本次 run 的证据。
|
||||
|
||||
@@ -303,21 +303,21 @@
|
||||
- Create: `reports/releases/.gitkeep`
|
||||
- Create: `docs/plans/2026-04-21-release-manifest-contract.md`
|
||||
|
||||
- [ ] `P2-A-01` 盘点所有依赖 `latest_file_or_empty` 的脚本入口。
|
||||
- [x] `P2-A-01` 盘点所有依赖 `latest_file_or_empty` 的脚本入口。
|
||||
完成标准:清单覆盖全部脚本和调用行。
|
||||
- [ ] `P2-A-02` 设计 `run_id` 生成规则。
|
||||
- [x] `P2-A-02` 设计 `run_id` 生成规则。
|
||||
完成标准:规则包含日期、提交号或流水号。
|
||||
- [ ] `P2-A-03` 设计发布目录结构 `reports/releases/<run_id>/...`。
|
||||
- [x] `P2-A-03` 设计发布目录结构 `reports/releases/<run_id>/...`。
|
||||
完成标准:目录草图写入 manifest 合同文档。
|
||||
- [ ] `P2-A-04` 设计 `manifest.json` 必填字段。
|
||||
- [x] `P2-A-04` 设计 `manifest.json` 必填字段。
|
||||
完成标准:至少包含 `run_id`、`commit_sha`、`env`、`artifact_paths`、`decision_inputs`。
|
||||
- [ ] `P2-A-05` 把 `staging_release_pipeline.sh` 的输入改成 manifest 读取方案草稿。
|
||||
- [x] `P2-A-05` 把 `staging_release_pipeline.sh` 的输入改成 manifest 读取方案草稿。
|
||||
完成标准:不再依赖“最新文件”。
|
||||
- [ ] `P2-A-06` 把 `staging_evidence_autofill.sh` 的输入改成 manifest 读取方案草稿。
|
||||
- [x] `P2-A-06` 把 `staging_evidence_autofill.sh` 的输入改成 manifest 读取方案草稿。
|
||||
完成标准:只消费本次 run 的工件。
|
||||
- [ ] `P2-A-07` 把 `tok007_release_recheck.sh` 的输入改成 manifest 读取方案草稿。
|
||||
- [x] `P2-A-07` 把 `tok007_release_recheck.sh` 的输入改成 manifest 读取方案草稿。
|
||||
完成标准:复检脚本不再扫历史目录。
|
||||
- [ ] `P2-A-08` 把 `final_decision_consistency_check.sh` 的输入改成 manifest 读取方案草稿。
|
||||
- [x] `P2-A-08` 把 `final_decision_consistency_check.sh` 的输入改成 manifest 读取方案草稿。
|
||||
完成标准:最终一致性检查绑定单次 run。
|
||||
|
||||
### Task P2-B: 把真实 staging 设为唯一发布硬门禁
|
||||
|
||||
126
docs/plans/2026-04-21-release-manifest-contract.md
Normal file
126
docs/plans/2026-04-21-release-manifest-contract.md
Normal file
@@ -0,0 +1,126 @@
|
||||
# 2026-04-21 Release Manifest Contract
|
||||
|
||||
## P2-A-01 依赖 `latest_file_or_empty` 的脚本入口
|
||||
|
||||
### `scripts/ci/staging_release_pipeline.sh`
|
||||
|
||||
1. `LATEST_STAGING_RUN_LOG`
|
||||
2. `LATEST_STAGE_REPORT`
|
||||
3. `LATEST_TOKEN_READINESS`
|
||||
4. `LATEST_TOK007_REPORT`
|
||||
5. `LATEST_PIPELINE_REPORT`
|
||||
|
||||
### `scripts/ci/staging_evidence_autofill.sh`
|
||||
|
||||
1. `STAGING_RUN_LOG`
|
||||
2. `SP_REPORT`
|
||||
3. `TOK021_REPORT`
|
||||
4. `TOK007_REPORT`
|
||||
5. `PIPELINE_REPORT`
|
||||
|
||||
### `scripts/ci/tok007_release_recheck.sh`
|
||||
|
||||
1. `TOK006_REPORT`
|
||||
2. `SP_REPORT`
|
||||
3. `TOK_RUNTIME_READINESS_REPORT`
|
||||
|
||||
### `scripts/ci/final_decision_consistency_check.sh`
|
||||
|
||||
1. `TOK007_FILE`
|
||||
2. `SP_FILE`
|
||||
|
||||
结论:
|
||||
|
||||
1. 当前四个脚本都通过“扫历史目录里最新文件”的方式串联证据。
|
||||
2. 这种方式无法证明输入属于同一次发布运行,必须被 `run_id + manifest` 方案替换。
|
||||
|
||||
## P2-A-02 `run_id` 生成规则
|
||||
|
||||
格式:
|
||||
|
||||
`YYYYMMDD_HHMMSS_<short_sha>_<env>[-rNN]`
|
||||
|
||||
规则:
|
||||
|
||||
1. `YYYYMMDD_HHMMSS` 使用执行开始时间。
|
||||
2. `<short_sha>` 使用 8 位提交号。
|
||||
3. `<env>` 使用本次发布环境标识,如 `staging`、`prod`、`localmock`。
|
||||
4. 若同秒内重复生成,追加 `-rNN` 顺序号,避免目录冲突。
|
||||
|
||||
## P2-A-03 发布目录结构
|
||||
|
||||
```text
|
||||
reports/releases/<run_id>/
|
||||
manifest.json
|
||||
logs/
|
||||
gate_verification/
|
||||
review_outputs/
|
||||
evidence/
|
||||
```
|
||||
|
||||
约束:
|
||||
|
||||
1. 同一次运行的产物只能写入自己的 `<run_id>` 目录。
|
||||
2. 历史目录只读,不允许被当前运行覆盖。
|
||||
|
||||
## P2-A-04 `manifest.json` 必填字段
|
||||
|
||||
最小字段:
|
||||
|
||||
- `run_id`
|
||||
- `commit_sha`
|
||||
- `env`
|
||||
- `created_at`
|
||||
- `source_env_file`
|
||||
- `artifact_paths`
|
||||
- `decision_inputs`
|
||||
|
||||
`artifact_paths` 最少应覆盖:
|
||||
|
||||
- `staging_release_pipeline_report`
|
||||
- `superpowers_release_pipeline_report`
|
||||
- `staging_evidence_autofill_report`
|
||||
- `tok007_recheck_report`
|
||||
- `final_decision_consistency_report`
|
||||
|
||||
`decision_inputs` 最少应覆盖:
|
||||
|
||||
- `staging_run_log`
|
||||
- `superpowers_stage_validation_report`
|
||||
- `token_runtime_readiness_report`
|
||||
- `tok006_gate_bundle_report`
|
||||
- `supply_gate_review_report`
|
||||
- `final_decision_report`
|
||||
|
||||
## P2-A-05 `staging_release_pipeline.sh` 输入改造草稿
|
||||
|
||||
方案:
|
||||
|
||||
1. 该脚本成为 manifest 的创建者。
|
||||
2. 启动时生成 `run_id` 和 `reports/releases/<run_id>/manifest.json`。
|
||||
3. 下游脚本统一接收 `--manifest <path>`。
|
||||
4. 不再从历史目录回扫 `LATEST_*` 文件,而是把本次步骤产物写回 manifest。
|
||||
|
||||
## P2-A-06 `staging_evidence_autofill.sh` 输入改造草稿
|
||||
|
||||
方案:
|
||||
|
||||
1. 增加 `--manifest` 作为首选输入。
|
||||
2. 只读取 manifest 中的 `decision_inputs` 和 `artifact_paths`。
|
||||
3. 当 manifest 缺少必填路径时直接失败,不再回退到“最新文件”。
|
||||
|
||||
## P2-A-07 `tok007_release_recheck.sh` 输入改造草稿
|
||||
|
||||
方案:
|
||||
|
||||
1. 增加 `--manifest` 输入。
|
||||
2. 复审所需的 TOK006 / stage validation / token readiness / SUP review / final decision 路径全部从 manifest 读取。
|
||||
3. 复检脚本只审当前 `run_id` 的证据,不扫描历史目录。
|
||||
|
||||
## P2-A-08 `final_decision_consistency_check.sh` 输入改造草稿
|
||||
|
||||
方案:
|
||||
|
||||
1. 增加 `--manifest` 输入。
|
||||
2. final decision、tok007 recheck、stage validation 三个来源全部绑定到同一个 `run_id`。
|
||||
3. 若 manifest 中任一路径缺失或跨 run_id,直接判定 `FAIL`。
|
||||
1
reports/releases/.gitkeep
Normal file
1
reports/releases/.gitkeep
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
@@ -4,11 +4,17 @@ set -euo pipefail
|
||||
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||
TS="$(date +%F_%H%M%S)"
|
||||
OUT_DIR="${ROOT_DIR}/reports/archive/gate_verification"
|
||||
RELEASES_DIR="${ROOT_DIR}/reports/releases"
|
||||
mkdir -p "${OUT_DIR}"
|
||||
|
||||
REPORT_FILE="${OUT_DIR}/final_decision_consistency_${TS}.md"
|
||||
LOG_FILE="${OUT_DIR}/final_decision_consistency_${TS}.log"
|
||||
|
||||
# Manifest migration design:
|
||||
# - preferred entry: --manifest <reports/releases/<run_id>/manifest.json>
|
||||
# - this script should bind final_decision, tok007_recheck and stage validation inputs
|
||||
# to one run_id and stop reading historical "latest" outputs
|
||||
|
||||
latest_file_or_empty() {
|
||||
local pattern="$1"
|
||||
local latest
|
||||
@@ -74,6 +80,10 @@ parse_machine_decision() {
|
||||
}
|
||||
|
||||
FINAL_DECISION_FILE="${ROOT_DIR}/review/final_decision_2026-03-31.md"
|
||||
# Planned manifest keys:
|
||||
# - decision_inputs.final_decision_report
|
||||
# - decision_inputs.tok007_recheck_report
|
||||
# - decision_inputs.superpowers_stage_validation_report
|
||||
TOK007_FILE="$(latest_file_or_empty "${ROOT_DIR}/review/outputs/tok007_release_recheck_*.md")"
|
||||
SP_FILE="$(latest_file_or_empty "${OUT_DIR}/superpowers_stage_validation_*.md")"
|
||||
|
||||
|
||||
@@ -3,12 +3,18 @@ set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||
OUT_DIR="${ROOT_DIR}/reports/archive/gate_verification"
|
||||
RELEASES_DIR="${ROOT_DIR}/reports/releases"
|
||||
TS="$(date +%F_%H%M%S)"
|
||||
OUT_FILE="${OUT_DIR}/staging_token_go_evidence_autofill_${TS}.md"
|
||||
LOG_FILE="${OUT_DIR}/staging_token_go_evidence_autofill_${TS}.log"
|
||||
|
||||
mkdir -p "${OUT_DIR}"
|
||||
|
||||
# Manifest migration design:
|
||||
# - preferred entry: --manifest <reports/releases/<run_id>/manifest.json>
|
||||
# - this script should read only decision_inputs/artifact_paths from the supplied manifest
|
||||
# - no future release evidence should be discovered by latest_file_or_empty()
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
@@ -211,6 +217,12 @@ while [[ $# -gt 0 ]]; do
|
||||
esac
|
||||
done
|
||||
|
||||
# Planned manifest keys:
|
||||
# - decision_inputs.staging_run_log
|
||||
# - decision_inputs.stage_report
|
||||
# - decision_inputs.token_runtime_readiness_report
|
||||
# - decision_inputs.tok007_recheck_report
|
||||
# - artifact_paths.superpowers_release_pipeline_report
|
||||
if [[ -z "${STAGING_RUN_LOG}" ]]; then
|
||||
STAGING_RUN_LOG="$(latest_file_or_empty "${OUT_DIR}/staging_run_*.log")"
|
||||
fi
|
||||
|
||||
@@ -10,12 +10,20 @@ else
|
||||
fi
|
||||
TS="$(date +%F_%H%M%S)"
|
||||
OUT_DIR="${ROOT_DIR}/reports/archive/gate_verification"
|
||||
RELEASES_DIR="${ROOT_DIR}/reports/releases"
|
||||
mkdir -p "${OUT_DIR}"
|
||||
|
||||
REPORT_FILE="${OUT_DIR}/staging_release_pipeline_${TS}.md"
|
||||
LOG_FILE="${OUT_DIR}/staging_release_pipeline_${TS}.log"
|
||||
ALLOW_LOCAL_MOCK_STAGING="${ALLOW_LOCAL_MOCK_STAGING:-0}"
|
||||
|
||||
# Manifest migration design:
|
||||
# - run_id format: YYYYMMDD_HHMMSS_<shortsha>_<env>[-rNN]
|
||||
# - release root: ${RELEASES_DIR}/<run_id>/
|
||||
# - manifest path: ${RELEASES_DIR}/<run_id>/manifest.json
|
||||
# - this script becomes the manifest seed writer and must pass the resolved manifest path
|
||||
# to downstream scripts instead of relying on latest_file_or_empty().
|
||||
|
||||
log() {
|
||||
echo "$1" | tee -a "${LOG_FILE}"
|
||||
}
|
||||
@@ -124,6 +132,12 @@ run_step \
|
||||
"Superpowers release pipeline with staging env" \
|
||||
"cd \"${ROOT_DIR}\" && STAGING_ENV_FILE=\"${ENV_FILE_REL}\" bash \"scripts/ci/superpowers_release_pipeline.sh\""
|
||||
|
||||
# Planned manifest inputs for staging_evidence_autofill.sh:
|
||||
# - decision_inputs.staging_run_log
|
||||
# - decision_inputs.stage_report
|
||||
# - decision_inputs.token_runtime_readiness_report
|
||||
# - decision_inputs.tok007_recheck_report
|
||||
# - artifact_paths.superpowers_release_pipeline_report
|
||||
LATEST_STAGING_RUN_LOG="$(latest_file_or_empty "${OUT_DIR}/staging_run_*.log")"
|
||||
LATEST_STAGE_REPORT="$(latest_file_or_empty "${OUT_DIR}/superpowers_stage_validation_*.md")"
|
||||
LATEST_TOKEN_READINESS="$(latest_file_or_empty "${OUT_DIR}/token_runtime_readiness_*.md")"
|
||||
|
||||
@@ -6,12 +6,18 @@ 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}"
|
||||
}
|
||||
@@ -100,6 +106,12 @@ extract_pass_fail_result() {
|
||||
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")"
|
||||
|
||||
Reference in New Issue
Block a user