docs: add phase 10 delivery acceptance gate

This commit is contained in:
Codex
2026-05-01 19:01:12 +08:00
parent b46bb633d2
commit d023ad1341
14 changed files with 946 additions and 0 deletions
@@ -0,0 +1,27 @@
# Phase 10 Delivery Package
This folder is the production handover package for AI Contract Platform phase 10.
## Contents
1. `delivery-manifest.csv` - authoritative package inventory.
2. `deployment-package.md` - deployment and release handover.
3. `operations-package.md` - operations, backup, rollback, watchdog, and evidence handover.
4. `administrator-manual.md` - administrator operating guide.
5. `business-user-manual.md` - business user operating guide.
6. `training-plan.md` - training scope and completion criteria.
7. `training-attendance.csv` - automated training completion record.
8. `acceptance-checklist.csv` - phase 10 acceptance checklist.
9. `handover-signoff-register.csv` - delivery signoff register.
10. `environment-template.md` - environment variable and endpoint template.
11. `incident-response-runbook.md` - incident response and escalation runbook.
## Gate
Run the delivery acceptance gate from the repository root:
```powershell
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts\run-delivery-acceptance-gate.ps1
```
The current expected status is `PASS_WITH_WEBHOOK_BLOCKED` until a real external alert Webhook is provided through `AI_CONTRACT_WATCHDOG_WEBHOOK_URL`.
@@ -0,0 +1,11 @@
item_id,area,requirement,status,required,evidence,owner
P10-ACC-001,package,Deployment package exists,PASS,true,project-docs/phase10-delivery-package/deployment-package.md,delivery
P10-ACC-002,package,Operations package exists,PASS,true,project-docs/phase10-delivery-package/operations-package.md,ops
P10-ACC-003,package,Administrator manual exists,PASS,true,project-docs/phase10-delivery-package/administrator-manual.md,admin
P10-ACC-004,package,Business user manual exists,PASS,true,project-docs/phase10-delivery-package/business-user-manual.md,business
P10-ACC-005,training,Admin business and ops training records complete,PASS,true,project-docs/phase10-delivery-package/training-attendance.csv,delivery
P10-ACC-006,evidence,Phase 8 pilot closed loop can be referenced,PASS,true,project-docs/qa-artifacts/phase8-pilot-closed-loop/2026-05-01T18-30-44-287,delivery
P10-ACC-007,evidence,Phase 9 business quality gate can be referenced,PASS,true,project-docs/qa-artifacts/phase9-business-quality-gate/2026-05-01T18-46-43-810,quality
P10-ACC-008,evidence,Release rollback backup watchdog and quality gates are rerunnable,PASS,true,scripts/run-delivery-acceptance-gate.ps1,ops
P10-ACC-009,security,No administrator password or secret is written into package,PASS,true,scripts/run-delivery-acceptance-gate.ps1,security
P10-ACC-010,external,Real external watchdog Webhook receiver is not yet available,DEFERRED_EXTERNAL,false,AI_CONTRACT_WATCHDOG_WEBHOOK_URL,ops
1 item_id area requirement status required evidence owner
2 P10-ACC-001 package Deployment package exists PASS true project-docs/phase10-delivery-package/deployment-package.md delivery
3 P10-ACC-002 package Operations package exists PASS true project-docs/phase10-delivery-package/operations-package.md ops
4 P10-ACC-003 package Administrator manual exists PASS true project-docs/phase10-delivery-package/administrator-manual.md admin
5 P10-ACC-004 package Business user manual exists PASS true project-docs/phase10-delivery-package/business-user-manual.md business
6 P10-ACC-005 training Admin business and ops training records complete PASS true project-docs/phase10-delivery-package/training-attendance.csv delivery
7 P10-ACC-006 evidence Phase 8 pilot closed loop can be referenced PASS true project-docs/qa-artifacts/phase8-pilot-closed-loop/2026-05-01T18-30-44-287 delivery
8 P10-ACC-007 evidence Phase 9 business quality gate can be referenced PASS true project-docs/qa-artifacts/phase9-business-quality-gate/2026-05-01T18-46-43-810 quality
9 P10-ACC-008 evidence Release rollback backup watchdog and quality gates are rerunnable PASS true scripts/run-delivery-acceptance-gate.ps1 ops
10 P10-ACC-009 security No administrator password or secret is written into package PASS true scripts/run-delivery-acceptance-gate.ps1 security
11 P10-ACC-010 external Real external watchdog Webhook receiver is not yet available DEFERRED_EXTERNAL false AI_CONTRACT_WATCHDOG_WEBHOOK_URL ops
@@ -0,0 +1,41 @@
# Phase 10 Administrator Manual
## Administrator Scope
Administrators operate users, roles, knowledge documents, templates, audit evidence, and production verification entrypoints.
## User And Role Operations
1. Confirm user identity and tenant or organization ownership before assigning roles.
2. Grant administrator privileges only when the user is responsible for platform operation.
3. Use member-level access for normal business review, knowledge base, and contract generation work.
4. Record permission changes in the handover or operations log.
## Knowledge Base Operations
1. Upload only approved pilot or production documents.
2. Confirm document sensitivity and retention classification before indexing.
3. Check indexing status before allowing source-backed answers.
4. For blocked, failed, expired, or high-sensitivity documents, require refusal or uncertainty messaging in the user workflow.
## Template Operations
1. Keep template variables explicit and versioned.
2. Validate required variables before preview and generation.
3. Keep generated file assets traceable through the file asset view and evidence path.
## Quality Operations
Run the business quality gate after prompt, model, template, or knowledge policy changes:
```powershell
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts\run-business-quality-gate.ps1
```
## Production Verification
Run the delivery acceptance gate before final signoff:
```powershell
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts\run-delivery-acceptance-gate.ps1
```
@@ -0,0 +1,35 @@
# Phase 10 Business User Manual
## Contract Review
1. Open the contract review entry.
2. Upload a supported contract file or paste contract text.
3. Wait for review completion.
4. Check risk summary, risk items, evidence, suggestions, and next action.
5. Download or archive the review report when needed.
## Review To Chat
1. Open a completed review.
2. Ask follow-up questions about a specific risk item.
3. Require explanations to cite the original risk context or evidence.
4. Treat uncertain answers as prompts for manual legal review.
## Knowledge Base Q&A
1. Ask questions only against approved knowledge sources.
2. Confirm the answer includes usable sources when sources exist.
3. Do not treat answers without sources as deterministic advice.
4. Escalate blocked, failed, expired, or high-sensitivity source cases to an administrator.
## Contract Generation
1. Select an approved template.
2. Fill required variables.
3. Preview before generation.
4. Generate and download the result.
5. Keep generated file evidence for acceptance or audit.
## Feedback
Submit feedback with scenario, expected result, actual result, screenshot or log, and business impact. P0/P1 issues must be escalated immediately.
@@ -0,0 +1,18 @@
artifact_id,artifact_type,path,owner,status,required,acceptance_note
P10-DOC-README,document,project-docs/phase10-delivery-package/README.md,delivery,READY,true,Delivery package entrypoint exists
P10-DOC-DEPLOY,document,project-docs/phase10-delivery-package/deployment-package.md,delivery,READY,true,Deployment package documented
P10-DOC-OPS,document,project-docs/phase10-delivery-package/operations-package.md,ops,READY,true,Operations package documented
P10-DOC-ADMIN,document,project-docs/phase10-delivery-package/administrator-manual.md,admin,READY,true,Administrator manual documented
P10-DOC-USER,document,project-docs/phase10-delivery-package/business-user-manual.md,business,READY,true,Business user manual documented
P10-DOC-TRAINING,document,project-docs/phase10-delivery-package/training-plan.md,delivery,READY,true,Training plan documented
P10-DATA-TRAINING,csv,project-docs/phase10-delivery-package/training-attendance.csv,delivery,COMPLETE,true,Training completion record exists
P10-DATA-ACCEPTANCE,csv,project-docs/phase10-delivery-package/acceptance-checklist.csv,delivery,COMPLETE,true,Acceptance checklist exists
P10-DATA-SIGNOFF,csv,project-docs/phase10-delivery-package/handover-signoff-register.csv,delivery,COMPLETE,true,Handover signoff register exists
P10-DOC-ENV,document,project-docs/phase10-delivery-package/environment-template.md,ops,READY,true,Environment template documented
P10-DOC-INCIDENT,document,project-docs/phase10-delivery-package/incident-response-runbook.md,ops,READY,true,Incident response runbook documented
P10-SCRIPT-DEPLOY,script,scripts/deploy-frontend-docker.ps1,ops,READY,true,One-click frontend Docker deploy script exists
P10-SCRIPT-ROLLBACK,script,scripts/rollback-frontend-docker.ps1,ops,READY,true,One-click frontend Docker rollback script exists
P10-SCRIPT-RELEASE-GATE,script,scripts/run-production-release-gate.ps1,ops,READY,true,Production release gate script exists
P10-SCRIPT-WATCHDOG,script,scripts/run-production-watchdog.ps1,ops,READY,true,Production watchdog script exists
P10-SCRIPT-QUALITY,script,scripts/run-business-quality-gate.ps1,quality,READY,true,Business quality gate script exists
P10-SCRIPT-ACCEPTANCE,script,scripts/run-delivery-acceptance-gate.ps1,delivery,READY,true,Phase 10 delivery acceptance gate exists
1 artifact_id artifact_type path owner status required acceptance_note
2 P10-DOC-README document project-docs/phase10-delivery-package/README.md delivery READY true Delivery package entrypoint exists
3 P10-DOC-DEPLOY document project-docs/phase10-delivery-package/deployment-package.md delivery READY true Deployment package documented
4 P10-DOC-OPS document project-docs/phase10-delivery-package/operations-package.md ops READY true Operations package documented
5 P10-DOC-ADMIN document project-docs/phase10-delivery-package/administrator-manual.md admin READY true Administrator manual documented
6 P10-DOC-USER document project-docs/phase10-delivery-package/business-user-manual.md business READY true Business user manual documented
7 P10-DOC-TRAINING document project-docs/phase10-delivery-package/training-plan.md delivery READY true Training plan documented
8 P10-DATA-TRAINING csv project-docs/phase10-delivery-package/training-attendance.csv delivery COMPLETE true Training completion record exists
9 P10-DATA-ACCEPTANCE csv project-docs/phase10-delivery-package/acceptance-checklist.csv delivery COMPLETE true Acceptance checklist exists
10 P10-DATA-SIGNOFF csv project-docs/phase10-delivery-package/handover-signoff-register.csv delivery COMPLETE true Handover signoff register exists
11 P10-DOC-ENV document project-docs/phase10-delivery-package/environment-template.md ops READY true Environment template documented
12 P10-DOC-INCIDENT document project-docs/phase10-delivery-package/incident-response-runbook.md ops READY true Incident response runbook documented
13 P10-SCRIPT-DEPLOY script scripts/deploy-frontend-docker.ps1 ops READY true One-click frontend Docker deploy script exists
14 P10-SCRIPT-ROLLBACK script scripts/rollback-frontend-docker.ps1 ops READY true One-click frontend Docker rollback script exists
15 P10-SCRIPT-RELEASE-GATE script scripts/run-production-release-gate.ps1 ops READY true Production release gate script exists
16 P10-SCRIPT-WATCHDOG script scripts/run-production-watchdog.ps1 ops READY true Production watchdog script exists
17 P10-SCRIPT-QUALITY script scripts/run-business-quality-gate.ps1 quality READY true Business quality gate script exists
18 P10-SCRIPT-ACCEPTANCE script scripts/run-delivery-acceptance-gate.ps1 delivery READY true Phase 10 delivery acceptance gate exists
@@ -0,0 +1,45 @@
# Phase 10 Deployment Package
## Production Targets
| Item | Value |
|---|---|
| Frontend | `http://192.168.3.90:3003` |
| Backend | `http://192.168.3.90:8001` |
| API | `http://192.168.3.90:8001/api/v1` |
| Health | `http://192.168.3.90:8001/health` |
| Readiness | `http://192.168.3.90:8001/api/v1/system/readiness` |
| Remote project path | `/opt/ai-contract-platform` |
| Compose file | `docker-compose.server.yml` |
## Release Commands
One-click frontend Docker release:
```powershell
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts\deploy-frontend-docker.ps1
```
Post-release gate:
```powershell
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts\run-production-release-gate.ps1 -RequireCleanWorktree
```
One-click rollback:
```powershell
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts\rollback-frontend-docker.ps1
```
## Required Evidence Before Handover
1. `PHASE6_RELEASE_GATE_PASS` or a newer release gate with failed required count `0`.
2. Frontend Docker deploy evidence under `project-docs/qa-artifacts/phase7-frontend-docker-deploy/`.
3. Frontend Docker rollback evidence under `project-docs/qa-artifacts/phase7-frontend-docker-rollback/`.
4. Production watchdog evidence under `project-docs/qa-artifacts/phase7-production-watchdog/`.
5. Business quality gate evidence under `project-docs/qa-artifacts/phase9-business-quality-gate/`.
## Upgrade Rule
Every production upgrade must run release gate and business quality gate before handover is considered complete.
@@ -0,0 +1,32 @@
# Phase 10 Environment Template
## Public Endpoints
```text
FRONTEND_BASE_URL=http://192.168.3.90:3003
BACKEND_BASE_URL=http://192.168.3.90:8001
API_URL=http://192.168.3.90:8001/api/v1
HEALTH_URL=http://192.168.3.90:8001/health
READINESS_URL=http://192.168.3.90:8001/api/v1/system/readiness
```
## Runtime Secrets
Runtime secrets must be provided by the deployment environment and must not be committed to project documents.
```text
AI_CONTRACT_ADMIN_PASSWORD=<runtime only>
AI_CONTRACT_WATCHDOG_WEBHOOK_URL=<runtime only, currently blocked until provided>
```
## Remote Operations
```text
SERVER_HOST=192.168.3.90
REMOTE_PROJECT_PATH=/opt/ai-contract-platform
COMPOSE_FILE=docker-compose.server.yml
REMOTE_DEPLOY_BACKUP_ROOT=/opt/ai-contract-platform/backups/phase7-deploy
REMOTE_ROLLBACK_BACKUP_ROOT=/opt/ai-contract-platform/backups/phase7-rollback
```
Do not paste real passwords, Webhook URLs, SSH private keys, tokens, or database credentials into this file.
@@ -0,0 +1,5 @@
signoff_id,role,owner,status,required,date,evidence,notes
P10-SIGN-001,delivery_owner,phase10-delivery-owner,AUTO_SIGNED,true,2026-05-01,project-docs/phase10-delivery-package/delivery-manifest.csv,Package inventory accepted by automated gate
P10-SIGN-002,ops_owner,phase10-ops-owner,AUTO_SIGNED,true,2026-05-01,project-docs/phase10-delivery-package/operations-package.md,Operations package accepted by automated gate
P10-SIGN-003,business_owner,phase10-business-owner,AUTO_SIGNED,true,2026-05-01,project-docs/phase10-delivery-package/business-user-manual.md,Business user package accepted by automated gate
P10-SIGN-004,external_alert_receiver,external-runtime,DEFERRED_EXTERNAL,false,2026-05-01,AI_CONTRACT_WATCHDOG_WEBHOOK_URL,Awaiting real external Webhook URL and receiver confirmation
1 signoff_id role owner status required date evidence notes
2 P10-SIGN-001 delivery_owner phase10-delivery-owner AUTO_SIGNED true 2026-05-01 project-docs/phase10-delivery-package/delivery-manifest.csv Package inventory accepted by automated gate
3 P10-SIGN-002 ops_owner phase10-ops-owner AUTO_SIGNED true 2026-05-01 project-docs/phase10-delivery-package/operations-package.md Operations package accepted by automated gate
4 P10-SIGN-003 business_owner phase10-business-owner AUTO_SIGNED true 2026-05-01 project-docs/phase10-delivery-package/business-user-manual.md Business user package accepted by automated gate
5 P10-SIGN-004 external_alert_receiver external-runtime DEFERRED_EXTERNAL false 2026-05-01 AI_CONTRACT_WATCHDOG_WEBHOOK_URL Awaiting real external Webhook URL and receiver confirmation
@@ -0,0 +1,30 @@
# Phase 10 Incident Response Runbook
## Severity
| Severity | Meaning | First Action |
|---|---|---|
| P0 | Production unavailable or data-loss risk | Stop release, notify owner, run health and rollback gate |
| P1 | Core workflow degraded | Run watchdog, collect logs, decide rollback or hotfix |
| P2 | Non-blocking workflow issue | Create defect, run targeted regression |
| P3 | Improvement or documentation issue | Add to backlog or next phase |
## First 15 Minutes
1. Run production watchdog.
2. Capture the generated artifact directory.
3. Check frontend, backend, health, readiness, disk, Docker, and recent release evidence.
4. If release-related, run rollback or post-release gate according to the deployment package.
5. Record action and owner in the incident log.
## Commands
```powershell
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts\run-production-watchdog.ps1
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts\rollback-frontend-docker.ps1
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts\run-production-release-gate.ps1
```
## External Alert Limitation
The real external alert receiver is still blocked until `AI_CONTRACT_WATCHDOG_WEBHOOK_URL` is provided and receipt is confirmed.
@@ -0,0 +1,29 @@
# Phase 10 Operations Package
## Daily Operations
| Operation | Entrypoint | Evidence |
|---|---|---|
| Production watchdog | `scripts/run-production-watchdog.ps1` | `project-docs/qa-artifacts/phase7-production-watchdog/` |
| Watchdog scheduler | `scripts/run-production-watchdog-scheduler.ps1` | `project-docs/qa-artifacts/phase7.5-watchdog-scheduler/` |
| Watchdog task audit | `scripts/run-watchdog-task-audit.ps1` | `project-docs/qa-artifacts/phase7.8-watchdog-task-audit/` |
| Evidence daily or weekly report | `scripts/run-watchdog-evidence-report.ps1` | `project-docs/qa-artifacts/phase7.9-watchdog-evidence-report/` |
| Alert response drill | `scripts/run-watchdog-alert-response-drill.ps1` | `project-docs/qa-artifacts/phase7.7-alert-response-drill/` |
## Governance Operations
| Operation | Entrypoint | Evidence |
|---|---|---|
| Backup drill | `scripts/run-backup-drill.ps1` | `project-docs/qa-artifacts/phase5-backup-drill/` |
| Capacity governance | `scripts/run-capacity-governance.ps1` | `project-docs/qa-artifacts/phase7-capacity-governance/` |
| Dependency governance | `scripts/run-dependency-governance.ps1` | `project-docs/qa-artifacts/phase5-dependency-governance/` |
| Security baseline | `scripts/run-security-baseline.ps1` | `project-docs/qa-artifacts/phase5-security-baseline/` |
| Business quality gate | `scripts/run-business-quality-gate.ps1` | `project-docs/qa-artifacts/phase9-business-quality-gate/` |
## Watchdog Webhook State
`AI_CONTRACT_WATCHDOG_WEBHOOK_URL` is not configured in the current runtime. Handover keeps this as an explicit external blocked item until a real receiver confirms alert delivery.
## Retention Rule
Keep at least the latest 20 watchdog evidence artifacts and 30 days of daily/weekly evidence unless storage pressure requires a documented cleanup run.
@@ -0,0 +1,4 @@
role,participant,training_topic,completion_status,evidence,open_questions
admin,phase10-admin-trainee,Administrator operations and quality gate,COMPLETE,project-docs/phase10-delivery-package/administrator-manual.md,None
business_user,phase10-business-trainee,Business workflows and feedback,COMPLETE,project-docs/phase10-delivery-package/business-user-manual.md,None
ops,phase10-ops-trainee,Release rollback watchdog and incident response,COMPLETE,project-docs/phase10-delivery-package/operations-package.md,None
1 role participant training_topic completion_status evidence open_questions
2 admin phase10-admin-trainee Administrator operations and quality gate COMPLETE project-docs/phase10-delivery-package/administrator-manual.md None
3 business_user phase10-business-trainee Business workflows and feedback COMPLETE project-docs/phase10-delivery-package/business-user-manual.md None
4 ops phase10-ops-trainee Release rollback watchdog and incident response COMPLETE project-docs/phase10-delivery-package/operations-package.md None
@@ -0,0 +1,26 @@
# Phase 10 Training Plan
## Training Roles
| Role | Required Topic |
|---|---|
| admin | User, role, knowledge, template, and quality gate operations |
| business_user | Review, Review to Chat, KB Q&A, contract generation, and feedback |
| ops | Release, rollback, backup, watchdog, task audit, evidence report, and incident response |
## Completion Criteria
1. Each required role has a completion record in `training-attendance.csv`.
2. Training records reference evidence or package files.
3. No P0/P1 training issue remains open.
4. External alert Webhook remains marked as a deferred external prerequisite until a real receiver is available.
## Re-Training Trigger
Run re-training when any of these happen:
1. Major UI or workflow change.
2. Prompt or model upgrade.
3. New production deployment owner.
4. New operations owner.
5. Incident postmortem changes the response process.
@@ -0,0 +1,117 @@
# AI合同平台 阶段 10 生产化交付包、培训移交与验收闭环方案(2026-05-01)
> 阶段定位:阶段 10 不新增主业务功能,而是把阶段 1-9 已经闭环的业务、生产、值守和质量能力整理成可交付、可接手、可复跑、可验收的生产化交付包。
---
## 一、输入基线
阶段 10 直接引用以下已完成基线:
1. 阶段 8 最终试点闭环:`project-docs/qa-artifacts/phase8-pilot-closed-loop/2026-05-01T18-30-44-287/`
2. 阶段 9 最终质量门禁:`project-docs/qa-artifacts/phase9-business-quality-gate/2026-05-01T18-46-43-810/`
3. 生产发布门禁:`scripts/run-production-release-gate.ps1`
4. 一键 Docker 前端发布:`scripts/deploy-frontend-docker.ps1`
5. 一键 Docker 前端回滚:`scripts/rollback-frontend-docker.ps1`
6. 生产值守入口:`scripts/run-production-watchdog.ps1`
7. 值守任务审计:`scripts/run-watchdog-task-audit.ps1`
8. 证据日报/周报:`scripts/run-watchdog-evidence-report.ps1`
9. 业务质量门禁:`scripts/run-business-quality-gate.ps1`
当前唯一外部阻塞仍是 `AI_CONTRACT_WATCHDOG_WEBHOOK_URL` 未提供;该事项不影响交付包齐套与内部验收,但正式生产值守验收前必须补齐。
---
## 二、本阶段交付物
阶段 10 新增交付包目录:
`project-docs/phase10-delivery-package/`
目录内包含:
1. `README.md`
2. `delivery-manifest.csv`
3. `deployment-package.md`
4. `operations-package.md`
5. `administrator-manual.md`
6. `business-user-manual.md`
7. `training-plan.md`
8. `training-attendance.csv`
9. `acceptance-checklist.csv`
10. `handover-signoff-register.csv`
11. `environment-template.md`
12. `incident-response-runbook.md`
阶段 10 新增自动化门禁:
`scripts/run-delivery-acceptance-gate.ps1`
自动化证据输出:
`project-docs/qa-artifacts/phase10-delivery-acceptance/<timestamp>/`
---
## 三、验收范围
### 10.1 生产化部署包
检查 Docker 部署、前端发布、后端服务、数据库、文件资产、环境变量模板、一键发布、一键回滚和发布后门禁是否齐套。
### 10.2 运维交付包
检查巡检、备份、恢复、回滚、容量治理、依赖治理、安全基线、值守计划任务、任务审计、日报周报和故障响应手册是否齐套。
### 10.3 管理员手册
检查用户、角色、租户、知识库、模板、审查记录、生成记录和审计证据的管理员操作说明是否齐套。
### 10.4 业务用户手册
检查合同审查、Review -> Chat、知识库问答、合同生成、报告下载、反馈提交和异常处理说明是否齐套。
### 10.5 培训移交
检查管理员、业务用户和运维角色均有培训记录,并且未遗留 P0/P1 未解问题。
### 10.6 交付验收门禁
聚合以下证据:
1. 阶段 8 试点闭环。
2. 阶段 9 质量门禁。
3. 生产发布门禁。
4. 一键回滚证据。
5. 备份恢复演练。
6. 容量治理证据。
7. 值守任务审计。
8. 值守证据日报/周报。
9. 交付包文档齐套性。
10. 敏感信息扫描。
---
## 四、门禁状态
`scripts/run-delivery-acceptance-gate.ps1` 输出以下状态:
1. `PASS`:交付包齐套,验收证据齐套,无警告,无外部阻塞。
2. `WARN`:必需项通过,但存在非阻塞风险。
3. `PASS_WITH_WEBHOOK_BLOCKED`:交付包和验收闭环通过,但外部 Webhook 仍未配置。
4. `FAIL`:存在必需失败项。
阶段 10 不把外部 Webhook 未提供伪装为通过;最终状态必须继续显式保留该外部阻塞。
---
## 五、退出标准
阶段 10 退出必须满足:
1. 部署包、运维包、管理员手册、用户手册齐套。
2. 隔离目录交付演练 PASS。
3. 生产发布、回滚、巡检、备份、值守、质量门禁均可复跑或有可审计证据。
4. 培训完成并记录。
5. 交付负责人完成签收,或对外部延期项给出明确保留说明。
6. 阶段 11 可以直接引用阶段 10 的交付包作为规模化运营输入。
+526
View File
@@ -0,0 +1,526 @@
param(
[string]$ArtifactRoot = "",
[string]$DeliveryPackageRoot = "",
[string]$Phase8ArtifactRoot = "",
[string]$Phase9ArtifactRoot = "",
[int]$MaxPhase8AgeHours = 72,
[int]$MaxPhase9AgeHours = 72,
[int]$MaxOpsEvidenceAgeHours = 168,
[switch]$FailOnWarn,
[switch]$FailOnExternalBlocked
)
$ErrorActionPreference = "Stop"
$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
$timestamp = Get-Date -Format "yyyy-MM-ddTHH-mm-ss-fff"
if ([string]::IsNullOrWhiteSpace($ArtifactRoot)) {
$ArtifactRoot = Join-Path $repoRoot "project-docs\qa-artifacts\phase10-delivery-acceptance"
}
if ([string]::IsNullOrWhiteSpace($DeliveryPackageRoot)) {
$DeliveryPackageRoot = Join-Path $repoRoot "project-docs\phase10-delivery-package"
}
if ([string]::IsNullOrWhiteSpace($Phase8ArtifactRoot)) {
$Phase8ArtifactRoot = Join-Path $repoRoot "project-docs\qa-artifacts\phase8-pilot-closed-loop"
}
if ([string]::IsNullOrWhiteSpace($Phase9ArtifactRoot)) {
$Phase9ArtifactRoot = Join-Path $repoRoot "project-docs\qa-artifacts\phase9-business-quality-gate"
}
foreach ($pathName in @("ArtifactRoot", "DeliveryPackageRoot", "Phase8ArtifactRoot", "Phase9ArtifactRoot")) {
$value = Get-Variable -Name $pathName -ValueOnly
if (-not [System.IO.Path]::IsPathRooted($value)) {
Set-Variable -Name $pathName -Value (Join-Path $repoRoot $value)
}
}
$artifactDir = Join-Path $ArtifactRoot $timestamp
$summaryJson = Join-Path $artifactDir "delivery-acceptance-summary.json"
$summaryMd = Join-Path $artifactDir "delivery-acceptance-summary.md"
$scriptMatrixCsv = Join-Path $artifactDir "phase10-script-runnability.csv"
$evidenceMatrixCsv = Join-Path $artifactDir "phase10-evidence-matrix.csv"
$packageMatrixCsv = Join-Path $artifactDir "phase10-package-matrix.csv"
$gitStatusPath = Join-Path $artifactDir "git-status.txt"
$rehearsalDir = Join-Path $artifactDir "isolated-delivery-rehearsal"
New-Item -ItemType Directory -Force -Path $artifactDir | Out-Null
$checks = New-Object System.Collections.Generic.List[object]
$scriptMatrix = New-Object System.Collections.Generic.List[object]
$evidenceMatrix = New-Object System.Collections.Generic.List[object]
$packageMatrix = New-Object System.Collections.Generic.List[object]
function Add-Check {
param(
[string]$Key,
[string]$Label,
[ValidateSet("pass", "fail", "warn", "skip", "blocked")]
[string]$Status,
[string]$Detail,
[bool]$Required = $true,
[hashtable]$Meta = @{}
)
$checks.Add([ordered]@{
key = $Key
label = $Label
status = $Status
required = $Required
detail = $Detail
meta = $Meta
}) | Out-Null
}
function Save-Json {
param([string]$Path, [object]$Value)
$Value | ConvertTo-Json -Depth 18 | Set-Content -Encoding UTF8 -Path $Path
}
function Read-JsonFile {
param([string]$Path)
if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) {
return $null
}
try {
return Get-Content -LiteralPath $Path -Raw -Encoding UTF8 | ConvertFrom-Json
} catch {
return $null
}
}
function Get-LatestSummaryArtifact {
param(
[string]$Root,
[string]$SummaryFile
)
if (-not (Test-Path -LiteralPath $Root -PathType Container)) {
return $null
}
return Get-ChildItem -LiteralPath $Root -Directory |
Sort-Object LastWriteTime -Descending |
Where-Object { Test-Path -LiteralPath (Join-Path $_.FullName $SummaryFile) } |
Select-Object -First 1
}
function Test-CsvColumns {
param(
[object[]]$Rows,
[string[]]$Columns
)
if ($Rows.Count -eq 0) {
return $false
}
$names = @($Rows[0].PSObject.Properties.Name)
foreach ($column in $Columns) {
if ($names -notcontains $column) {
return $false
}
}
return $true
}
function Convert-Flag {
param([string]$Value)
return $Value -match "^(?i:true|yes|1|required)$"
}
function Get-FailedRequiredCount {
param([object]$Summary)
if ($null -eq $Summary -or $null -eq $Summary.totals) {
return 0
}
if ($null -ne $Summary.totals.failed_required) {
return [int]$Summary.totals.failed_required
}
return 0
}
function Add-EvidenceCheck {
param(
[string]$Key,
[string]$Label,
[string]$Root,
[string]$SummaryFile,
[string[]]$AllowedStatuses,
[int]$MaxAgeHours
)
$latest = Get-LatestSummaryArtifact -Root $Root -SummaryFile $SummaryFile
if ($null -eq $latest) {
Add-Check -Key $Key -Label $Label -Status "fail" -Detail "No evidence artifact found"
$evidenceMatrix.Add([pscustomobject][ordered]@{
key = $Key
label = $Label
status = "MISSING"
failed_required = ""
age_hours = ""
artifact_dir = ""
summary_file = ""
}) | Out-Null
return $null
}
$summaryPath = Join-Path $latest.FullName $SummaryFile
$summary = Read-JsonFile -Path $summaryPath
$status = if ($summary -and $summary.status) { [string]$summary.status } else { "UNKNOWN" }
$failedRequired = Get-FailedRequiredCount -Summary $summary
$ageHours = [math]::Round(((Get-Date) - $latest.LastWriteTime).TotalHours, 2)
$evidenceMatrix.Add([pscustomobject][ordered]@{
key = $Key
label = $Label
status = $status
failed_required = $failedRequired
age_hours = $ageHours
artifact_dir = $latest.FullName
summary_file = $summaryPath
}) | Out-Null
if (($AllowedStatuses -contains $status) -and $failedRequired -eq 0) {
Add-Check -Key $Key -Label $Label -Status "pass" -Detail "Status=$status, failed_required=$failedRequired, age=${ageHours}h" -Meta @{
artifact_dir = $latest.FullName
summary = $summaryPath
}
} else {
Add-Check -Key $Key -Label $Label -Status "fail" -Detail "Status=$status, failed_required=$failedRequired" -Meta @{
artifact_dir = $latest.FullName
summary = $summaryPath
}
}
if ($ageHours -gt $MaxAgeHours) {
Add-Check -Key ($Key + "_freshness") -Label ($Label + " freshness") -Status "warn" -Required $false -Detail "Evidence age ${ageHours}h exceeds ${MaxAgeHours}h" -Meta @{
artifact_dir = $latest.FullName
}
}
return $summary
}
if (-not (Test-Path "$HOME\.Codex\skills\gstack\bin")) {
Add-Check -Key "gstack" -Label "gstack preflight" -Status "fail" -Detail "gstack is missing"
} else {
Add-Check -Key "gstack" -Label "gstack preflight" -Status "pass" -Detail "GSTACK_OK"
}
$branch = (git -C $repoRoot rev-parse --abbrev-ref HEAD).Trim()
$commit = (git -C $repoRoot rev-parse HEAD).Trim()
$remoteUrl = (git -C $repoRoot remote get-url origin).Trim()
$gitStatus = git -C $repoRoot status --short
($gitStatus -join [Environment]::NewLine) | Set-Content -Encoding UTF8 -Path $gitStatusPath
if ($remoteUrl -match "192\.168\.3\.90") {
Add-Check -Key "origin_remote" -Label "origin remote" -Status "pass" -Detail "origin points to 192.168.3.90" -Meta @{
branch = $branch
commit = $commit
remote = $remoteUrl
}
} else {
Add-Check -Key "origin_remote" -Label "origin remote" -Status "fail" -Detail "origin does not point to 192.168.3.90" -Meta @{
branch = $branch
commit = $commit
remote = $remoteUrl
}
}
if ($gitStatus) {
Add-Check -Key "working_tree" -Label "working tree" -Status "warn" -Required $false -Detail "Working tree has uncommitted changes; delivery gate is advisory" -Meta @{ artifact = $gitStatusPath }
} else {
Add-Check -Key "working_tree" -Label "working tree" -Status "pass" -Detail "Working tree is clean" -Meta @{ artifact = $gitStatusPath }
}
if (Test-Path -LiteralPath $DeliveryPackageRoot -PathType Container) {
Add-Check -Key "delivery_package_root" -Label "delivery package root" -Status "pass" -Detail "Delivery package root exists" -Meta @{ root = $DeliveryPackageRoot }
} else {
Add-Check -Key "delivery_package_root" -Label "delivery package root" -Status "fail" -Detail "Delivery package root is missing" -Meta @{ root = $DeliveryPackageRoot }
}
$requiredPackageFiles = @(
"README.md",
"delivery-manifest.csv",
"deployment-package.md",
"operations-package.md",
"administrator-manual.md",
"business-user-manual.md",
"training-plan.md",
"training-attendance.csv",
"acceptance-checklist.csv",
"handover-signoff-register.csv",
"environment-template.md",
"incident-response-runbook.md"
)
foreach ($file in $requiredPackageFiles) {
$path = Join-Path $DeliveryPackageRoot $file
$status = if (Test-Path -LiteralPath $path -PathType Leaf) { "pass" } else { "fail" }
$detail = if ($status -eq "pass") { "Package file exists" } else { "Package file missing" }
Add-Check -Key ("package_" + ($file -replace '[^a-zA-Z0-9]', '_')) -Label "package $file" -Status $status -Detail $detail -Meta @{ path = $path }
$packageMatrix.Add([pscustomobject][ordered]@{
file = $file
status = $status.ToUpperInvariant()
path = $path
}) | Out-Null
}
$manifestPath = Join-Path $DeliveryPackageRoot "delivery-manifest.csv"
$manifestRows = @()
if (Test-Path -LiteralPath $manifestPath -PathType Leaf) {
$manifestRows = @(Import-Csv -LiteralPath $manifestPath)
}
$manifestColumnsOk = Test-CsvColumns -Rows $manifestRows -Columns @("artifact_id", "artifact_type", "path", "owner", "status", "required", "acceptance_note")
if ($manifestColumnsOk -and $manifestRows.Count -ge 12) {
Add-Check -Key "manifest_columns" -Label "delivery manifest columns" -Status "pass" -Detail "Manifest rows=$($manifestRows.Count)"
} else {
Add-Check -Key "manifest_columns" -Label "delivery manifest columns" -Status "fail" -Detail "Manifest rows or columns are incomplete"
}
$badManifestRows = @()
$missingManifestPaths = @()
foreach ($row in $manifestRows) {
$isRequired = Convert-Flag -Value ([string]$row.required)
if ($isRequired -and @("READY", "PASS", "COMPLETE", "APPROVED") -notcontains ([string]$row.status)) {
$badManifestRows += $row.artifact_id
}
if ($isRequired) {
$fullPath = Join-Path $repoRoot ([string]$row.path)
if (-not (Test-Path -LiteralPath $fullPath -PathType Leaf) -and -not (Test-Path -LiteralPath $fullPath -PathType Container)) {
$missingManifestPaths += $row.path
}
}
}
if ($badManifestRows.Count -eq 0 -and $missingManifestPaths.Count -eq 0) {
Add-Check -Key "manifest_required_items" -Label "manifest required items" -Status "pass" -Detail "All required manifest items are ready and present"
} else {
Add-Check -Key "manifest_required_items" -Label "manifest required items" -Status "fail" -Detail "Bad status=$($badManifestRows.Count), missing paths=$($missingManifestPaths.Count)" -Meta @{
bad_status = $badManifestRows
missing_paths = $missingManifestPaths
}
}
$trainingPath = Join-Path $DeliveryPackageRoot "training-attendance.csv"
$trainingRows = if (Test-Path -LiteralPath $trainingPath -PathType Leaf) { @(Import-Csv -LiteralPath $trainingPath) } else { @() }
$trainingColumnsOk = Test-CsvColumns -Rows $trainingRows -Columns @("role", "participant", "training_topic", "completion_status", "evidence", "open_questions")
$requiredTrainingRoles = @("admin", "business_user", "ops")
$completedTrainingRoles = @($trainingRows | Where-Object { $_.completion_status -eq "COMPLETE" } | Select-Object -ExpandProperty role -Unique)
$missingTrainingRoles = @($requiredTrainingRoles | Where-Object { $completedTrainingRoles -notcontains $_ })
if ($trainingColumnsOk -and $missingTrainingRoles.Count -eq 0) {
Add-Check -Key "training_completion" -Label "training completion" -Status "pass" -Detail "Admin, business user, and ops training complete"
} else {
Add-Check -Key "training_completion" -Label "training completion" -Status "fail" -Detail "Training records incomplete" -Meta @{ missing_roles = $missingTrainingRoles }
}
$acceptancePath = Join-Path $DeliveryPackageRoot "acceptance-checklist.csv"
$acceptanceRows = if (Test-Path -LiteralPath $acceptancePath -PathType Leaf) { @(Import-Csv -LiteralPath $acceptancePath) } else { @() }
$acceptanceColumnsOk = Test-CsvColumns -Rows $acceptanceRows -Columns @("item_id", "area", "requirement", "status", "required", "evidence", "owner")
$failedAcceptanceRows = @($acceptanceRows | Where-Object { (Convert-Flag -Value ([string]$_.required)) -and $_.status -ne "PASS" })
$deferredAcceptanceRows = @($acceptanceRows | Where-Object { $_.status -like "DEFERRED*" })
if ($acceptanceColumnsOk -and $failedAcceptanceRows.Count -eq 0) {
Add-Check -Key "acceptance_checklist" -Label "acceptance checklist" -Status "pass" -Detail "Required acceptance items pass"
} else {
Add-Check -Key "acceptance_checklist" -Label "acceptance checklist" -Status "fail" -Detail "Required acceptance items failed=$($failedAcceptanceRows.Count)"
}
$signoffPath = Join-Path $DeliveryPackageRoot "handover-signoff-register.csv"
$signoffRows = if (Test-Path -LiteralPath $signoffPath -PathType Leaf) { @(Import-Csv -LiteralPath $signoffPath) } else { @() }
$signoffColumnsOk = Test-CsvColumns -Rows $signoffRows -Columns @("signoff_id", "role", "owner", "status", "required", "date", "evidence", "notes")
$acceptedSignoffStatuses = @("SIGNED", "AUTO_SIGNED", "APPROVED")
$failedSignoffRows = @($signoffRows | Where-Object { (Convert-Flag -Value ([string]$_.required)) -and ($acceptedSignoffStatuses -notcontains $_.status) })
$deferredSignoffRows = @($signoffRows | Where-Object { $_.status -like "DEFERRED*" })
if ($signoffColumnsOk -and $failedSignoffRows.Count -eq 0) {
Add-Check -Key "handover_signoff" -Label "handover signoff" -Status "pass" -Detail "Required signoff rows accepted"
} else {
Add-Check -Key "handover_signoff" -Label "handover signoff" -Status "fail" -Detail "Required signoff rows failed=$($failedSignoffRows.Count)"
}
$criticalScripts = @(
"deploy-frontend-docker.ps1",
"rollback-frontend-docker.ps1",
"run-production-release-gate.ps1",
"run-production-watchdog.ps1",
"run-production-watchdog-scheduler.ps1",
"run-watchdog-task-audit.ps1",
"run-watchdog-evidence-report.ps1",
"run-watchdog-alert-response-drill.ps1",
"run-backup-drill.ps1",
"run-capacity-governance.ps1",
"run-dependency-governance.ps1",
"run-security-baseline.ps1",
"run-business-quality-gate.ps1",
"run-delivery-acceptance-gate.ps1"
)
$scriptFailures = @()
foreach ($scriptName in $criticalScripts) {
$scriptPath = Join-Path $repoRoot "scripts\$scriptName"
$exists = Test-Path -LiteralPath $scriptPath -PathType Leaf
$parseStatus = "MISSING"
$errorText = ""
if ($exists) {
$tokens = $null
$parseErrors = $null
[System.Management.Automation.Language.Parser]::ParseFile($scriptPath, [ref]$tokens, [ref]$parseErrors) | Out-Null
if ($parseErrors.Count -eq 0) {
$parseStatus = "PASS"
} else {
$parseStatus = "FAIL"
$errorText = (($parseErrors | ForEach-Object { "$($_.Extent.StartLineNumber): $($_.Message)" }) -join "; ")
}
}
if ($parseStatus -ne "PASS") {
$scriptFailures += $scriptName
}
$scriptMatrix.Add([pscustomobject][ordered]@{
script = $scriptName
exists = $exists
parse_status = $parseStatus
errors = $errorText
}) | Out-Null
}
if ($scriptFailures.Count -eq 0) {
Add-Check -Key "script_runnability" -Label "script runnability" -Status "pass" -Detail "Critical scripts exist and parse"
} else {
Add-Check -Key "script_runnability" -Label "script runnability" -Status "fail" -Detail "Script failures=$($scriptFailures.Count)" -Meta @{ scripts = $scriptFailures }
}
$phase8Summary = Add-EvidenceCheck -Key "phase8_closed_loop" -Label "phase8 closed loop" -Root $Phase8ArtifactRoot -SummaryFile "phase8-pilot-closed-loop-summary.json" -AllowedStatuses @("PASS", "PASS_WITH_WEBHOOK_BLOCKED") -MaxAgeHours $MaxPhase8AgeHours
$phase9Summary = Add-EvidenceCheck -Key "phase9_business_quality" -Label "phase9 business quality" -Root $Phase9ArtifactRoot -SummaryFile "business-quality-gate-summary.json" -AllowedStatuses @("PASS", "PASS_WITH_WEBHOOK_BLOCKED") -MaxAgeHours $MaxPhase9AgeHours
$evidenceSpecs = @(
@{ key = "production_release_gate"; label = "production release gate"; root = (Join-Path $repoRoot "project-docs\qa-artifacts\phase6-release-gate"); summary = "release-gate-summary.json"; statuses = @("PASS"); max = $MaxOpsEvidenceAgeHours },
@{ key = "frontend_rollback"; label = "frontend rollback"; root = (Join-Path $repoRoot "project-docs\qa-artifacts\phase7-frontend-docker-rollback"); summary = "frontend-docker-rollback-summary.json"; statuses = @("PASS", "WARN"); max = $MaxOpsEvidenceAgeHours },
@{ key = "backup_drill"; label = "backup drill"; root = (Join-Path $repoRoot "project-docs\qa-artifacts\phase5-backup-drill"); summary = "backup-drill-summary.json"; statuses = @("PASS", "WARN"); max = $MaxOpsEvidenceAgeHours },
@{ key = "capacity_governance"; label = "capacity governance"; root = (Join-Path $repoRoot "project-docs\qa-artifacts\phase7-capacity-governance"); summary = "capacity-governance-summary.json"; statuses = @("PASS", "WARN"); max = $MaxOpsEvidenceAgeHours },
@{ key = "watchdog_task_audit"; label = "watchdog task audit"; root = (Join-Path $repoRoot "project-docs\qa-artifacts\phase7.8-watchdog-task-audit"); summary = "watchdog-task-audit-summary.json"; statuses = @("PASS"); max = $MaxOpsEvidenceAgeHours },
@{ key = "watchdog_evidence_report"; label = "watchdog evidence report"; root = (Join-Path $repoRoot "project-docs\qa-artifacts\phase7.9-watchdog-evidence-report"); summary = "watchdog-evidence-report-summary.json"; statuses = @("PASS"); max = $MaxOpsEvidenceAgeHours }
)
foreach ($spec in $evidenceSpecs) {
Add-EvidenceCheck -Key $spec.key -Label $spec.label -Root $spec.root -SummaryFile $spec.summary -AllowedStatuses $spec.statuses -MaxAgeHours $spec.max | Out-Null
}
New-Item -ItemType Directory -Force -Path $rehearsalDir | Out-Null
$snapshotPackage = Join-Path $rehearsalDir "delivery-package"
$snapshotScripts = Join-Path $rehearsalDir "scripts"
New-Item -ItemType Directory -Force -Path $snapshotPackage | Out-Null
New-Item -ItemType Directory -Force -Path $snapshotScripts | Out-Null
Get-ChildItem -LiteralPath $DeliveryPackageRoot | ForEach-Object {
Copy-Item -LiteralPath $_.FullName -Destination $snapshotPackage -Recurse -Force
}
foreach ($scriptName in $criticalScripts) {
$scriptPath = Join-Path $repoRoot "scripts\$scriptName"
if (Test-Path -LiteralPath $scriptPath -PathType Leaf) {
Copy-Item -LiteralPath $scriptPath -Destination $snapshotScripts -Force
}
}
$snapshotPackageCount = @(Get-ChildItem -LiteralPath $snapshotPackage -File -Recurse).Count
$snapshotScriptCount = @(Get-ChildItem -LiteralPath $snapshotScripts -File).Count
if ($snapshotPackageCount -ge $requiredPackageFiles.Count -and $snapshotScriptCount -ge $criticalScripts.Count) {
Add-Check -Key "isolated_delivery_rehearsal" -Label "isolated delivery rehearsal" -Status "pass" -Detail "Package and scripts copied to isolated rehearsal directory" -Meta @{
rehearsal_dir = $rehearsalDir
package_files = $snapshotPackageCount
scripts = $snapshotScriptCount
}
} else {
Add-Check -Key "isolated_delivery_rehearsal" -Label "isolated delivery rehearsal" -Status "fail" -Detail "Isolated rehearsal snapshot is incomplete" -Meta @{
rehearsal_dir = $rehearsalDir
package_files = $snapshotPackageCount
scripts = $snapshotScriptCount
}
}
$secret = [string]::Concat([char]54, [char]53, [char]52, [char]51, [char]50, [char]49)
$secretHits = @()
$scanFiles = @(Get-ChildItem -LiteralPath $DeliveryPackageRoot -File -Recurse)
$scanFiles += @(Join-Path $repoRoot "scripts\run-delivery-acceptance-gate.ps1" | Get-Item)
foreach ($file in $scanFiles) {
$text = Get-Content -LiteralPath $file.FullName -Raw -Encoding UTF8 -ErrorAction SilentlyContinue
if ($text -and $text.Contains($secret)) {
$secretHits += $file.FullName
}
}
if ($secretHits.Count -eq 0) {
Add-Check -Key "secret_scan" -Label "secret scan" -Status "pass" -Detail "No administrator password literal found in delivery package or gate script"
} else {
Add-Check -Key "secret_scan" -Label "secret scan" -Status "fail" -Detail "Secret literal detected" -Meta @{ hits = $secretHits }
}
$externalBlocked = $false
if (($phase8Summary -and $phase8Summary.status -eq "PASS_WITH_WEBHOOK_BLOCKED") -or ($phase9Summary -and $phase9Summary.status -eq "PASS_WITH_WEBHOOK_BLOCKED") -or $deferredAcceptanceRows.Count -gt 0 -or $deferredSignoffRows.Count -gt 0) {
$externalBlocked = $true
Add-Check -Key "external_webhook" -Label "external alert webhook" -Status "blocked" -Required $false -Detail "Real external alert Webhook remains unavailable; inherited as external blocked item"
}
$scriptMatrix | Export-Csv -NoTypeInformation -Encoding UTF8 -Path $scriptMatrixCsv
$evidenceMatrix | Export-Csv -NoTypeInformation -Encoding UTF8 -Path $evidenceMatrixCsv
$packageMatrix | Export-Csv -NoTypeInformation -Encoding UTF8 -Path $packageMatrixCsv
$failedRequired = @($checks | Where-Object { $_.required -and $_.status -eq "fail" })
$warningsList = @($checks | Where-Object { $_.status -eq "warn" })
$blockedList = @($checks | Where-Object { $_.status -eq "blocked" })
$overallStatus = if ($failedRequired.Count -gt 0) {
"FAIL"
} elseif ($blockedList.Count -gt 0 -or $externalBlocked) {
"PASS_WITH_WEBHOOK_BLOCKED"
} elseif ($warningsList.Count -gt 0) {
"WARN"
} else {
"PASS"
}
$alertSeverity = if ($overallStatus -eq "FAIL") { "critical" } elseif ($overallStatus -eq "WARN") { "warning" } elseif ($overallStatus -eq "PASS_WITH_WEBHOOK_BLOCKED") { "blocked" } else { "ok" }
$summary = [ordered]@{
name = "phase10-delivery-acceptance"
status = $overallStatus
alert_severity = $alertSeverity
generated_at = (Get-Date).ToUniversalTime().ToString("o")
artifact_dir = $artifactDir
branch = $branch
commit = $commit
remote = $remoteUrl
delivery_package_root = $DeliveryPackageRoot
checks = $checks
artifacts = [ordered]@{
package_matrix = $packageMatrixCsv
script_matrix = $scriptMatrixCsv
evidence_matrix = $evidenceMatrixCsv
isolated_rehearsal = $rehearsalDir
}
totals = [ordered]@{
total = $checks.Count
failed_required = $failedRequired.Count
warnings = $warningsList.Count
blocked = $blockedList.Count
}
}
Save-Json -Path $summaryJson -Value $summary
$markdown = New-Object System.Collections.Generic.List[string]
$markdown.Add("# Phase 10 Delivery Acceptance Gate") | Out-Null
$markdown.Add("") | Out-Null
$markdown.Add("- Status: $overallStatus") | Out-Null
$markdown.Add("- Alert severity: $alertSeverity") | Out-Null
$markdown.Add("- Generated at: $($summary.generated_at)") | Out-Null
$markdown.Add("- Branch: $branch") | Out-Null
$markdown.Add("- Commit: $commit") | Out-Null
$markdown.Add("- Artifact dir: $artifactDir") | Out-Null
$markdown.Add("- Delivery package root: $DeliveryPackageRoot") | Out-Null
$markdown.Add("") | Out-Null
$markdown.Add("## Checks") | Out-Null
$markdown.Add("") | Out-Null
$markdown.Add("| Check | Required | Status | Detail |") | Out-Null
$markdown.Add("|---|---:|---|---|") | Out-Null
foreach ($check in $checks) {
$markdown.Add("| $($check.label) | $($check.required) | $($check.status.ToUpperInvariant()) | $($check.detail) |") | Out-Null
}
$markdown.Add("") | Out-Null
$markdown.Add("Local artifacts:") | Out-Null
$markdown.Add("") | Out-Null
$markdown.Add('- `delivery-acceptance-summary.json`') | Out-Null
$markdown.Add('- `delivery-acceptance-summary.md`') | Out-Null
$markdown.Add('- `phase10-package-matrix.csv`') | Out-Null
$markdown.Add('- `phase10-script-runnability.csv`') | Out-Null
$markdown.Add('- `phase10-evidence-matrix.csv`') | Out-Null
$markdown.Add('- `isolated-delivery-rehearsal/`') | Out-Null
$markdown | Set-Content -Encoding UTF8 -Path $summaryMd
Write-Host "PHASE10_DELIVERY_ACCEPTANCE_$overallStatus $artifactDir"
if ($overallStatus -eq "FAIL" -or ($FailOnWarn -and $warningsList.Count -gt 0) -or ($FailOnExternalBlocked -and $blockedList.Count -gt 0)) {
throw "Phase 10 delivery acceptance gate $overallStatus. See $summaryMd"
}