docs(08-08-production-deployment-validation): 补齐部署验证规范与证据边界

这个提交包含在:
2026-08-08 11:11:31 +08:00
父节点 5e2d038938
当前提交 65e22c60c7
共修改 9 个文件,包含 445 行新增和 6 行删除
+83 -3
查看文件
@@ -1442,7 +1442,7 @@ bash scripts/qa/run-automatic-backup-contract.sh
### 6. Tests Required
- `bash -n deploy/trialrun/deploy.sh deploy/trialrun/deploy-existing.sh deploy/trialrun/preflight-remote.sh`.
- `bash -n deploy/trialrun/deploy.sh deploy/trialrun/deploy-existing.sh deploy/trialrun/preflight-remote.sh deploy/trialrun/production-preflight-remote.sh`.
- `bash scripts/qa/run-deployment-contract-refresh-contract.sh` must prove multi-failure aggregation reaches the final item, output redaction, forced-command exact matching, four failure categories, four build drop-ins and four timer checks.
- `node deploy/trialrun/validate-env-contract.js`.
- `cd server && npm test -- tests/unit/scripts/deployment-safety-contract.test.js`.
@@ -1455,8 +1455,8 @@ bash scripts/qa/run-automatic-backup-contract.sh
```bash
# working_dir may be the Compose config directory, not the repository root.
REMOTE_DIR="$(docker inspect <server> --format '<working_dir-label>')" \
bash deploy/trialrun/deploy.sh
REMOTE_DIR="$(docker inspect <server> --format '<working_dir-label>')" \
bash deploy/trialrun/deploy.sh
```
#### Correct
@@ -1472,6 +1472,86 @@ DEPLOY_SERVER=<approved-ssh-target> \
# recovery runbook to prove one complete backup and off-host freshness.
```
## Scenario: Production Migration-First Target Gate
### 1. Scope / Trigger
- Trigger: an approved existing-host release whose candidate commit contains a
Prisma migration, especially the contract `terminated` workspace migration.
- Purpose: prove the remote target identity and migration history before any
schema write, then preserve the state-based rollback boundary.
### 2. Signatures
- Wrapper: `deploy/trialrun/deploy-existing.sh`.
- Local orchestrator: `deploy/trialrun/production-preflight.mjs`.
- Remote read-only helper: `deploy/trialrun/production-preflight-remote.sh`.
- Required process inputs: `EXPECTED_PRODUCTION_ORIGIN`,
`EXPECTED_PRODUCTION_DB_NAME`, and `EXPECTED_PENDING_MIGRATIONS`.
### 3. Contracts
- Production R2 is the inverse of the local migration task: the gate must prove
the target is the expected production HTTPS origin and database identity, and
reject loopback, local regression, staging and trialrun identities. It must
never infer production from an SSH alias, Compose label or directory name.
- The strict production-validation wrapper rejects unpublished-commit overrides;
disaster-recovery exceptions use a separately approved recovery flow.
- Expected target values remain process-only. The local orchestrator sends only
one-way digests to the remote helper and records stable codes, not values,
credentials, paths or raw environment content.
- The candidate manifest is generated from the verified commit. Before
`deploy.sh`, the remote helper confirms the runtime `DATABASE_URL` host and
database identity, then runs `prisma migrate status`. Raw stdout/stderr stays
in the controlled execution environment; the local report contains only a
redacted status copy. The helper compares `_prisma_migrations` with the
candidate manifest. Pending must exactly equal the explicit allowlist;
pending IDs reported by status must belong to the candidate manifest;
failed, rolled-back, unfinished, diverged or unknown history fails closed.
- The preflight helper is read-only: it does not run `migrate dev`, reset,
`db push`, `migrate resolve`, seed, DDL or business writes. `deploy.sh` is
reached only after target and pre-status gates pass.
- The post-deploy status is a separate evidence item and must be manually read;
the wrapper re-runs the read-only helper with an empty pending allowlist
before backup-contract refresh, and a successful exit code alone is
insufficient.
- Each preflight run removes only its two known report files before SSH; a
reused report directory must never leave an old PASS status artifact in place.
- When the strict wrapper invokes `deploy.sh`, it sets
`DEPLOY_STATUS_OUTPUT_MODE=quiet`; the legacy status check must not echo raw
datasource output. Detailed evidence comes from the controlled pre/post
helper artifacts.
- `terminated` count defines a state window: zero rows means `OPEN`; the first
committed row closes it. Once closed, an old application that does not know
`terminated` cannot be restored and the new columns are never auto-dropped;
recovery is roll-forward or a compatible hotfix.
- The target identity must remain unchanged between the read-only preflight and
the schema write; if a controlled change freeze cannot be established, stop
before `deploy.sh` rather than relying on post-status to repair a wrong-target
write.
### 4. Validation & Error Matrix
- Missing or invalid expected target input -> stop before SSH mutation.
- Target hash, runtime mode, cookie security or DB identity mismatch -> stop
before `deploy.sh`.
- Status output missing/unreadable, failed/rolled-back/diverged history or an
unknown pending migration -> `PAUSED`; do not reset or resolve in place.
- Pending set differs from the approved allowlist -> `PAUSED` and retain the
status artifact for human review.
- `terminated` count greater than zero -> record `rollbackWindow=CLOSED` and
disallow compatibility rollback; this task never creates such a row.
### 5. Tests Required
- `node --check deploy/trialrun/production-preflight.mjs`.
- `bash -n deploy/trialrun/production-preflight-remote.sh`.
- `node deploy/trialrun/validate-env-contract.js`.
- `cd server && npm test -- tests/unit/scripts/deployment-safety-contract.test.js`.
- Static ordering must prove production preflight precedes `deploy.sh`, and the
remote status marker precedes migration-history reconciliation. Fixtures must
reject loopback/staging target identities without invoking SSH.
## Scenario: Environment Recovery Classification And Secret Custody
### 1. Scope / Trigger