记录(08-08-production-deployment-execution): 收口生产部署证据

这个提交包含在:
2026-08-08 22:08:16 +08:00
父节点 0224ad83d7
当前提交 d5fb2eca23
共修改 4 个文件,包含 68 行新增和 31 行删除
+22 -1
查看文件
@@ -1496,6 +1496,13 @@ bash scripts/qa/run-automatic-backup-contract.sh
old runtime artifacts, so retrieve a failed stage log before any approved
retry. Keeping an interactive execution handle is not a substitute for this
second copy.
- An SSH transport loss after a stage starts makes the remote deployment state
`UNKNOWN`; it does not prove that the remote shell or later stages stopped.
Before choosing retry or rollback, inspect every candidate-stage log in
order, then run independent read-only migration reconciliation, active
runtime SHA and public readiness checks. If migration/application switching
completed but contract refresh did not, classify partial success and repair
only the refresh contract; never replay the deployment.
### 4. Validation & Error Matrix
@@ -1515,7 +1522,8 @@ bash scripts/qa/run-automatic-backup-contract.sh
- Long stage exits non-zero -> preserve its original status and relative log
reference, stop under `set -e`, and do not enter the next stage.
- SSH stream disappears -> use the already-written remote log for diagnosis;
do not repeat the deployment merely to recreate console output.
treat remote completion as unknown, inspect all stage logs plus post-status,
and do not repeat the deployment merely to recreate console output.
- Runtime log directory/file mode is broader than `0700`/`0600`, stage output
has no log reference, or a bare build/init/server-switch call bypasses the
wrapper -> deployment evidence contract fails locally.
@@ -1526,6 +1534,9 @@ bash scripts/qa/run-automatic-backup-contract.sh
- Good: a long stage writes its complete remote log, returns a stable relative
reference and preserves the exact non-zero child status even if the
interactive stream is incomplete.
- Good: SSH closes after the first stage marker; all three remote logs and
post-status prove migration/application completion, so operations run only
the exact contract refresh and finish with aggregate read-only preflight.
- Good: ordinary and forced-command identities pass separately, all aggregate items are reported, deployment passes, root helper updates only fixed build drop-ins, and four timers remain enabled/active.
- Good: a broken-root recovery creates a clean published-commit source tree, proves one environment candidate against running containers without exposing values, copies it with mode `0600`, deploys with `SYNC_ENV=0`, then updates the backup contracts and completes a real off-host backup.
- Base: first initialization uses reviewed explicit parameters and `DEPLOY_DATA_MODE=initialize`; it does not pretend an existing unit is available.
@@ -1534,6 +1545,9 @@ bash scripts/qa/run-automatic-backup-contract.sh
- Bad: grant NOPASSWD to a repository installer, point forced-command at a deploy-user-writable script, reuse an unrestricted root key, stop aggregation after its first failure, or downgrade refresh failure to a warning.
- Bad: run `docker compose build/run/up` as bare SSH-stream-only calls, lose the
terminal tail, then retry production solely to recover diagnostics.
- Bad: interpret a local SSH 255/disconnect as proof that the remote command
stopped, then replay migration/application deployment without checking later
stage logs or the active runtime.
### 6. Tests Required
@@ -1545,6 +1559,9 @@ bash scripts/qa/run-automatic-backup-contract.sh
- Static deployment tests must prove all three long stages use the persistent
wrapper, output is redirected to the mode-`0600` file, the error branch
captures `$?` immediately, and the former bare calls are absent.
- A disconnect recovery fixture must model missing local PASS output while
later remote stage logs exist; the expected decision is read-only
reconciliation and partial-success refresh, with no second deploy command.
- A controlled recovery must additionally record: exact published source commit, per-key PASS set/date without values, byte-copy/owner/mode PASS, new-SHA service/timer contract PASS, a successful complete backup, and a successful off-host freshness check. Old candidates remain untouched until a separately approved cleanup.
### 7. Wrong vs Correct
@@ -1576,6 +1593,10 @@ DEPLOY_SERVER=<approved-ssh-target> \
# Correct: the remote file is authoritative and the stream carries a safe ref.
run_logged_deploy_stage "build-init" "${compose_cmd[@]}" build init
# A disconnect means UNKNOWN, not failed-before-write:
# inspect build-init/run-init/build-switch-server logs and post-status first.
# If app/schema are current and only backup_build is stale, run refresh only.
```
## Scenario: Production Migration-First Target Gate