fix: harden review and verifier governance

This commit is contained in:
phamnazage-jpg
2026-05-29 18:48:48 +08:00
parent 88833fac8b
commit e999d31b25
133 changed files with 2538 additions and 159 deletions

View File

@@ -0,0 +1,37 @@
#!/usr/bin/env bash
set -euo pipefail
BACKLOG_PATH="${1:?backlog path required}"
python3 - <<'PY' "$BACKLOG_PATH"
from pathlib import Path
import re
import sys
text = Path(sys.argv[1]).read_text(encoding='utf-8')
lines = text.splitlines()
inside = False
current_rows = []
for line in lines:
if line.startswith('## 当前未修复问题速查表'):
inside = True
continue
if inside and line.startswith('---'):
break
if inside and line.startswith('|') and not line.startswith('| #') and not line.startswith('|---'):
current_rows.append(line)
matches = re.findall(r'freshness_hint=same-day-blocker-switch old=([^ ]+) new=([^\n ]+)', text)
for old, new in matches:
old_variants = {
old.lower(),
old.replace('-', ' ').lower(),
old.replace(' ', '-').lower(),
}
for row in current_rows:
row_lower = row.lower()
if any(variant and variant in row_lower for variant in old_variants):
print('stale blocker still present in current table', file=sys.stderr)
raise SystemExit(1)
print('BACKLOG_BLOCKER_FRESHNESS_GUARD: PASS')
PY

View File

@@ -0,0 +1,41 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$ROOT_DIR"
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT
BAD_BACKLOG="$TMP_DIR/backlog.md"
cat > "$BAD_BACKLOG" <<'EOF'
## 当前未修复问题速查表(截至 2026-05-29 15:10
| # | 问题 | 优先级 | 首次暴露 | 修复状态 | 影响次数 |
|---|------|--------|----------|----------|----------|
| 46 | sensenova-live smoke FAIL | P1 | 05-28 15:10 | ❌ 未修复 | 1 次 |
| 48 | xfyun-live smoke FAIL 导致 live_run SKIP 传导链 | P1 | 05-29 15:10 | ❌ 未修复 | 首次暴露 |
---
### 2026-05-29 15:10afternoon-review cron
- freshness_hint=same-day-blocker-switch old=sensenova-live new=xfyun-live
EOF
set +e
bash scripts/review/backlog_blocker_freshness_guard.sh "$BAD_BACKLOG" >/tmp/backlog_blocker_bad.out 2>&1
BAD_RC=$?
set -e
[[ "$BAD_RC" -ne 0 ]]
grep -q 'stale blocker still present in current table' /tmp/backlog_blocker_bad.out
GOOD_BACKLOG="$TMP_DIR/backlog-good.md"
cat > "$GOOD_BACKLOG" <<'EOF'
## 当前未修复问题速查表(截至 2026-05-29 15:10
| # | 问题 | 优先级 | 首次暴露 | 修复状态 | 影响次数 |
|---|------|--------|----------|----------|----------|
| 48 | xfyun-live smoke FAIL 导致 live_run SKIP 传导链 | P1 | 05-29 15:10 | ❌ 未修复 | 首次暴露 |
---
### 2026-05-29 15:10afternoon-review cron
- freshness_hint=same-day-blocker-switch old=sensenova-live new=xfyun-live
EOF
bash scripts/review/backlog_blocker_freshness_guard.sh "$GOOD_BACKLOG" >/tmp/backlog_blocker_good.out 2>&1
grep -q 'BACKLOG_BLOCKER_FRESHNESS_GUARD: PASS' /tmp/backlog_blocker_good.out

View File

@@ -0,0 +1,25 @@
#!/usr/bin/env bash
set -euo pipefail
BACKLOG_PATH="${1:?backlog path required}"
NOW_RAW="${LLM_NOW:-$(date '+%Y-%m-%d %H:%M')}"
python3 - <<'PY' "$BACKLOG_PATH" "$NOW_RAW"
from pathlib import Path
from datetime import datetime
import re
import sys
text = Path(sys.argv[1]).read_text(encoding='utf-8')
now = datetime.strptime(sys.argv[2], '%Y-%m-%d %H:%M')
match = re.search(r'## 当前未修复问题速查表(截至 ([0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2})', text)
if not match:
print('missing current table timestamp', file=sys.stderr)
raise SystemExit(1)
seen = datetime.strptime(match.group(1), '%Y-%m-%d %H:%M')
age_minutes = int((now - seen).total_seconds() // 60)
if age_minutes > 180:
print('stale current truth snapshot', file=sys.stderr)
raise SystemExit(1)
print(f'BACKLOG_FRESHNESS age_minutes={age_minutes} status=fresh')
PY

View File

@@ -0,0 +1,36 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$ROOT_DIR"
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT
STALE_FILE="$TMP_DIR/stale-backlog.md"
cat > "$STALE_FILE" <<'EOF'
## 当前未修复问题速查表(截至 2026-05-01 09:30
| # | 问题 | 优先级 | 首次暴露 | 修复状态 | 影响次数 |
|---|------|--------|----------|----------|----------|
| 25 | stale current truth | P2 | 05-16 09:30 | ❌ 未修复 | 2 次 |
---
EOF
set +e
LLM_NOW='2026-05-29 12:00' bash scripts/review/backlog_current_freshness_guard.sh "$STALE_FILE" >/tmp/backlog_freshness_bad.out 2>&1
STALE_RC=$?
set -e
[[ "$STALE_RC" -ne 0 ]]
grep -q 'stale current truth snapshot' /tmp/backlog_freshness_bad.out
FRESH_FILE="$TMP_DIR/fresh-backlog.md"
cat > "$FRESH_FILE" <<'EOF'
## 当前未修复问题速查表(截至 2026-05-29 11:55
| # | 问题 | 优先级 | 首次暴露 | 修复状态 | 影响次数 |
|---|------|--------|----------|----------|----------|
| 25 | stale current truth | P2 | 05-16 09:30 | ❌ 未修复 | 2 次 |
---
EOF
LLM_NOW='2026-05-29 12:00' bash scripts/review/backlog_current_freshness_guard.sh "$FRESH_FILE" >/tmp/backlog_freshness_good.out 2>&1
grep -q 'BACKLOG_FRESHNESS age_minutes=5 status=fresh' /tmp/backlog_freshness_good.out

View File

@@ -0,0 +1,28 @@
#!/usr/bin/env bash
set -euo pipefail
BACKLOG_PATH="${1:?backlog path required}"
python3 - <<'PY' "$BACKLOG_PATH"
from pathlib import Path
import sys
text = Path(sys.argv[1]).read_text(encoding='utf-8')
lines = text.splitlines()
inside = False
rows = []
for line in lines:
if line.startswith('## 当前未修复问题速查表'):
inside = True
continue
if inside and line.startswith('---'):
break
if inside and line.startswith('|') and not line.startswith('| #') and not line.startswith('|---'):
rows.append(line)
resolved = [row for row in rows if '✅ 已修复' in row or '✅ 已完成' in row or '✅ 已恢复' in row]
print(f'BACKLOG_CURRENT_TABLE rows={len(rows)} resolved_rows={len(resolved)}')
if resolved:
print('resolved rows still present in current table', file=sys.stderr)
raise SystemExit(1)
PY

View File

@@ -0,0 +1,38 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$ROOT_DIR"
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT
BAD_FILE="$TMP_DIR/bad-backlog.md"
cat > "$BAD_FILE" <<'EOF'
## 当前未修复问题速查表(截至 2026-05-29 12:00
| # | 问题 | 优先级 | 首次暴露 | 修复状态 | 影响次数 |
|---|------|--------|----------|----------|----------|
| 1 | old resolved item | P1 | 05-01 10:00 | ✅ 已修复 | 1 次 |
| 2 | still open | P1 | 05-01 11:00 | ❌ 未修复 | 2 次 |
---
EOF
set +e
bash scripts/review/backlog_current_table_guard.sh "$BAD_FILE" >/tmp/backlog_guard_bad.out 2>&1
BAD_RC=$?
set -e
[[ "$BAD_RC" -ne 0 ]]
grep -q 'resolved rows still present in current table' /tmp/backlog_guard_bad.out
GOOD_FILE="$TMP_DIR/good-backlog.md"
cat > "$GOOD_FILE" <<'EOF'
## 当前未修复问题速查表(截至 2026-05-29 12:00
| # | 问题 | 优先级 | 首次暴露 | 修复状态 | 影响次数 |
|---|------|--------|----------|----------|----------|
| 2 | still open | P1 | 05-01 11:00 | ❌ 未修复 | 2 次 |
| 3 | partial item | P1 | 05-01 12:00 | ⚠️ 部分 | 3 次 |
---
EOF
bash scripts/review/backlog_current_table_guard.sh "$GOOD_FILE" >/tmp/backlog_guard_good.out 2>&1
grep -q 'BACKLOG_CURRENT_TABLE rows=2 resolved_rows=0' /tmp/backlog_guard_good.out

View File

@@ -0,0 +1,31 @@
#!/usr/bin/env bash
set -euo pipefail
BACKLOG_PATH="${1:?backlog path required}"
python3 - <<'PY' "$BACKLOG_PATH"
from pathlib import Path
import re
import sys
text = Path(sys.argv[1]).read_text(encoding='utf-8')
lines = text.splitlines()
inside = False
current_rows = []
for line in lines:
if line.startswith('## 当前未修复问题速查表'):
inside = True
continue
if inside and line.startswith('---'):
break
if inside and line.startswith('|') and not line.startswith('| #') and not line.startswith('|---'):
current_rows.append(line)
resolved_ids = set(re.findall(r'#### 问题 ([0-9]+) 状态更新:已修复(从 current 表移除)', text))
for issue_id in resolved_ids:
for row in current_rows:
if row.startswith(f'| {issue_id} |') or row.startswith(f'| {issue_id} |'.replace(' ', '')):
print('resolved issue still present in current table', file=sys.stderr)
raise SystemExit(1)
print('BACKLOG_REVOCATION_GUARD: PASS')
PY

View File

@@ -0,0 +1,40 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$ROOT_DIR"
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT
BAD_BACKLOG="$TMP_DIR/backlog.md"
cat > "$BAD_BACKLOG" <<'EOF'
## 当前未修复问题速查表(截至 2026-05-29 15:10
| # | 问题 | 优先级 | 首次暴露 | 修复状态 | 影响次数 |
|---|------|--------|----------|----------|----------|
| 33 | 已证伪 blocker 缺少自动降级/撤销机制 | P1 | 05-18 09:30 | ❌ 未修复 | 2 次 |
---
#### 问题 33 状态更新:已修复(从 current 表移除)
- 结论:问题 33 已关闭。
EOF
set +e
bash scripts/review/backlog_revocation_guard.sh "$BAD_BACKLOG" >/tmp/backlog_revocation_bad.out 2>&1
BAD_RC=$?
set -e
[[ "$BAD_RC" -ne 0 ]]
grep -q 'resolved issue still present in current table' /tmp/backlog_revocation_bad.out
GOOD_BACKLOG="$TMP_DIR/backlog-good.md"
cat > "$GOOD_BACKLOG" <<'EOF'
## 当前未修复问题速查表(截至 2026-05-29 15:10
| # | 问题 | 优先级 | 首次暴露 | 修复状态 | 影响次数 |
|---|------|--------|----------|----------|----------|
| 34 | 局部 smoke 已通过后缺少全局 blocker 切换提示 | P1 | 05-18 15:10 | ❌ 未修复 | 1 次 |
---
#### 问题 33 状态更新:已修复(从 current 表移除)
- 结论:问题 33 已关闭。
EOF
bash scripts/review/backlog_revocation_guard.sh "$GOOD_BACKLOG" >/tmp/backlog_revocation_good.out 2>&1
grep -q 'BACKLOG_REVOCATION_GUARD: PASS' /tmp/backlog_revocation_good.out

View File

@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -euo pipefail
REPORT_PATH="${1:?review file required}"
CONTENT="$(cat "$REPORT_PATH")"
if [[ "$CONTENT" == *'替换'* ]]; then
if [[ "$CONTENT" != *'freshness_hint=same-day-blocker-switch'* ]]; then
echo "missing blocker switch freshness hint" >&2
exit 1
fi
fi
echo "BLOCKER_SWITCH_GUARD: PASS"

View File

@@ -0,0 +1,31 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$ROOT_DIR"
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT
BAD_FILE="$TMP_DIR/review-switch.txt"
cat > "$BAD_FILE" <<'EOF'
### 2026-05-29 15:10afternoon-review cron
- xfyun-live smoke FAIL 替换 sensenova-live
EOF
set +e
bash scripts/review/blocker_switch_guard.sh "$BAD_FILE" >/tmp/blocker_switch_bad.out 2>&1
BAD_RC=$?
set -e
[[ "$BAD_RC" -ne 0 ]]
grep -q 'missing blocker switch freshness hint' /tmp/blocker_switch_bad.out
GOOD_FILE="$TMP_DIR/review-switch-good.txt"
cat > "$GOOD_FILE" <<'EOF'
### 2026-05-29 15:10afternoon-review cron
- xfyun-live smoke FAIL 替换 sensenova-live
- freshness_hint=same-day-blocker-switch old=sensenova-live new=xfyun-live
EOF
bash scripts/review/blocker_switch_guard.sh "$GOOD_FILE" >/tmp/blocker_switch_good.out 2>&1
grep -q 'BLOCKER_SWITCH_GUARD: PASS' /tmp/blocker_switch_good.out

View File

@@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -euo pipefail
ROW_FILE="${1:?row file required}"
ROW_CONTENT="$(cat "$ROW_FILE")"
if [[ "$ROW_CONTENT" == *'✅ 已修复'* || "$ROW_CONTENT" == *'✅ 已完成'* || "$ROW_CONTENT" == *'✅ 已恢复'* ]]; then
echo "resolved current row should be revoked from current table" >&2
exit 1
fi
echo "CURRENT_ROW_REVOCATION_GUARD: PASS"

View File

@@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$ROOT_DIR"
TMP_FILE="$(mktemp)"
trap 'rm -f "$TMP_FILE"' EXIT
bash scripts/verify_phase6.sh >"$TMP_FILE" 2>&1 || true
bash scripts/review/global_blocker_switch_guard.sh "$TMP_FILE"
grep -q '^BLOCKER_SWITCH class=' "$TMP_FILE"

View File

@@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -euo pipefail
STATUS_FILE="${1:?phase status file required}"
CONTENT="$(cat "$STATUS_FILE")"
if [[ "$CONTENT" == *'importer_smoke_gate_result=PASS'* && "$CONTENT" == *'ROOT_CAUSE class='* && "$CONTENT" != *'ROOT_CAUSE class=none'* ]]; then
if [[ "$CONTENT" != *'BLOCKER_SWITCH class=global-blocker-shift'* ]]; then
echo "missing global blocker switch hint" >&2
exit 1
fi
fi
if [[ "$CONTENT" == *'importer_smoke_gate_result=FAIL'* && "$CONTENT" == *'live_run_result=SKIPPED'* ]]; then
if [[ "$CONTENT" != *'BLOCKER_SWITCH class=global-blocker-shift'* ]]; then
echo "missing global blocker switch hint" >&2
exit 1
fi
fi
echo "GLOBAL_BLOCKER_SWITCH_GUARD: PASS"

View File

@@ -0,0 +1,33 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$ROOT_DIR"
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT
BAD_FILE="$TMP_DIR/phase6.txt"
cat > "$BAD_FILE" <<'EOF'
[PASS] importer_smoke_gate_result=PASS 新增导入器 smoke gate 通过
[FAIL] live_run_result=FAIL 主链路真实采集失败
ROOT_CAUSE class=primary_pipeline_failure source=live_run summary=主链路真实采集失败
EOF
set +e
bash scripts/review/global_blocker_switch_guard.sh "$BAD_FILE" >/tmp/global_blocker_bad.out 2>&1
BAD_RC=$?
set -e
[[ "$BAD_RC" -ne 0 ]]
grep -q 'missing global blocker switch hint' /tmp/global_blocker_bad.out
GOOD_FILE="$TMP_DIR/phase6-good.txt"
cat > "$GOOD_FILE" <<'EOF'
[PASS] importer_smoke_gate_result=PASS 新增导入器 smoke gate 通过
[FAIL] live_run_result=FAIL 主链路真实采集失败
ROOT_CAUSE class=primary_pipeline_failure source=live_run summary=主链路真实采集失败
BLOCKER_SWITCH class=global-blocker-shift old=importer_smoke_gate new=live_run
EOF
bash scripts/review/global_blocker_switch_guard.sh "$GOOD_FILE" >/tmp/global_blocker_good.out 2>&1
grep -q 'GLOBAL_BLOCKER_SWITCH_GUARD: PASS' /tmp/global_blocker_good.out

View File

@@ -0,0 +1,23 @@
#!/usr/bin/env bash
set -euo pipefail
classify_live_run_failure() {
local live_tail="${1:-}"
local normalized
normalized="$(printf '%s' "$live_tail" | tr '[:upper:]' '[:lower:]')"
case "$normalized" in
*"api key"*|*"database_url"*|*"must provide"*|*"未设置"*|*"permission denied"*|*"role does not exist"*|*"relation does not exist"*)
printf '%s\n' 'precondition_missing'
;;
*"signature_guard"*|*"unexpected status 403"*|*"unexpected status 502"*|*"unexpected status 503"*|*"unexpected status 504"*|*"no pricing cards found"*|*"no model rows parsed"*|*"no model overview cards parsed"*|*"context deadline exceeded"*|*"client.timeout"*|*"i/o timeout"*|*"tls handshake timeout"*|*"transport closed"*|*"connection reset"*|*"connection refused"*|*"no such host"*)
printf '%s\n' 'external_provider_failure'
;;
*)
printf '%s\n' 'primary_pipeline_failure'
;;
esac
}
[[ "$(classify_live_run_failure 'OPENROUTER_API_KEY 未设置,无法执行真实采集')" == 'precondition_missing' ]]
[[ "$(classify_live_run_failure 'import_vertex_pricing: read https://cloud.google.com/...: context deadline exceeded (Client.Timeout or context cancellation while reading body)')" == 'external_provider_failure' ]]
[[ "$(classify_live_run_failure 'insert report_runs failed: duplicate key value violates unique constraint')" == 'primary_pipeline_failure' ]]

View File

@@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -euo pipefail
STATUS_FILE="${1:?status file required}"
CONTENT="$(cat "$STATUS_FILE")"
if [[ "$CONTENT" != *'PARTIAL_OUTPUT_STATUS complete=false source=artifact-required conclusion=conservative'* ]]; then
echo "missing conservative partial-output template" >&2
exit 1
fi
echo "PARTIAL_OUTPUT_GUARD: PASS"

View File

@@ -0,0 +1,30 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$ROOT_DIR"
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT
BAD_FILE="$TMP_DIR/bad-output.txt"
cat > "$BAD_FILE" <<'EOF'
long command output line 1
long command output line 2
EOF
set +e
bash scripts/review/partial_output_guard.sh "$BAD_FILE" >/tmp/partial_bad.out 2>&1
BAD_RC=$?
set -e
[[ "$BAD_RC" -ne 0 ]]
grep -q 'missing conservative partial-output template' /tmp/partial_bad.out
GOOD_FILE="$TMP_DIR/good-output.txt"
cat > "$GOOD_FILE" <<'EOF'
PARTIAL_OUTPUT_STATUS complete=false source=artifact-required conclusion=conservative
artifact_hint=artifact://123
EOF
bash scripts/review/partial_output_guard.sh "$GOOD_FILE" >/tmp/partial_good.out 2>&1
grep -q 'PARTIAL_OUTPUT_GUARD: PASS' /tmp/partial_good.out

View File

@@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -euo pipefail
classify_live_run_provider() {
local live_tail="${1:-}"
local normalized
normalized="$(printf '%s' "$live_tail" | tr '[:upper:]' '[:lower:]')"
case "$normalized" in
*"import_vertex_pricing"*) printf '%s\n' 'vertex_pricing' ;;
*"import_cloudflare_pricing"*|*"cloudflare_pricing"*) printf '%s\n' 'cloudflare_pricing' ;;
*"import_perplexity_pricing"*|*"perplexity_pricing"*) printf '%s\n' 'perplexity_pricing' ;;
*"import_xfyun_pricing"*|*"xfyun_pricing"*) printf '%s\n' 'xfyun_pricing' ;;
*) printf '%s\n' 'unknown_external_provider' ;;
esac
}
[[ "$(classify_live_run_provider 'import_vertex_pricing: read https://cloud.google.com/...: context deadline exceeded')" == 'vertex_pricing' ]]
[[ "$(classify_live_run_provider 'import_cloudflare_pricing: fetch https://developers.cloudflare.com/...: unexpected status 403')" == 'cloudflare_pricing' ]]
[[ "$(classify_live_run_provider 'import_perplexity_pricing: no model rows parsed')" == 'perplexity_pricing' ]]
[[ "$(classify_live_run_provider 'import_xfyun_pricing: no pricing cards found')" == 'xfyun_pricing' ]]

View File

@@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$ROOT_DIR"
TMP_FILE="$(mktemp)"
trap 'rm -f "$TMP_FILE"' EXIT
bash scripts/verify_phase6.sh >"$TMP_FILE" 2>&1 || true
bash scripts/review/release_semantics_guard.sh "$TMP_FILE"
grep -q '^RELEASE_SEMANTICS class=' "$TMP_FILE"

View File

@@ -0,0 +1,11 @@
#!/usr/bin/env bash
set -euo pipefail
STATUS_FILE="${1:?phase status file required}"
if ! grep -q '^RELEASE_SEMANTICS class=' "$STATUS_FILE"; then
echo "missing release semantics summary" >&2
exit 1
fi
echo "RELEASE_SEMANTICS_GUARD: PASS"

View File

@@ -0,0 +1,29 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$ROOT_DIR"
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT
BAD_FILE="$TMP_DIR/bad-phase6.txt"
cat > "$BAD_FILE" <<'EOF'
[WARN] window_gate_result=WARN 最近 7 次采集成功率未达 95%仅外部文档站失败external_provider_failure_onlystability_label=recovered-external-incident
EOF
set +e
bash scripts/review/release_semantics_guard.sh "$BAD_FILE" >/tmp/release_semantics_bad.out 2>&1
BAD_RC=$?
set -e
[[ "$BAD_RC" -ne 0 ]]
grep -q 'missing release semantics summary' /tmp/release_semantics_bad.out
GOOD_FILE="$TMP_DIR/good-phase6.txt"
cat > "$GOOD_FILE" <<'EOF'
[WARN] window_gate_result=WARN 最近 7 次采集成功率未达 95%仅外部文档站失败external_provider_failure_onlystability_label=recovered-external-incident
RELEASE_SEMANTICS class=degraded-external-provider gate=window_gate policy=release-allowed-with-warning
EOF
bash scripts/review/release_semantics_guard.sh "$GOOD_FILE" >/tmp/release_semantics_good.out 2>&1
grep -q 'RELEASE_SEMANTICS_GUARD: PASS' /tmp/release_semantics_good.out

View File

@@ -0,0 +1,35 @@
#!/usr/bin/env bash
set -euo pipefail
REPORT_PATH="${1:?review report path required}"
NEXT_BLOCK="$(python3 - <<'PY' "$REPORT_PATH"
from pathlib import Path
import sys
text = Path(sys.argv[1]).read_text(encoding='utf-8')
lines = text.splitlines()
inside = False
buf = []
for line in lines:
if line.startswith('## '):
if inside:
break
inside = line.strip() == '## Next'
continue
if inside:
buf.append(line)
print('\n'.join(buf))
PY
)"
if [[ -z "${NEXT_BLOCK//[[:space:]]/}" ]]; then
echo "missing actionable next step: ## Next block is empty" >&2
exit 1
fi
if ! printf '%s\n' "$NEXT_BLOCK" | grep -Eq '(^- .*处理|^- .*修复|^- .*新增|^- .*更新|^- .*验证|^- .*运行|^- .*同步|^- .*接入|^- .*排查|^[0-9]+\..*(处理|修复|新增|更新|验证|运行|同步|接入|排查)|处理问题|修复问题|新增.*guard|接入.*链)'; then
echo "missing actionable next step: ## Next does not contain executable action" >&2
exit 1
fi
echo "REVIEW_ACTION_GUARD: PASS"

View File

@@ -0,0 +1,47 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$ROOT_DIR"
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT
BAD_REPORT="$TMP_DIR/bad-review.md"
cat > "$BAD_REPORT" <<'EOF'
## Context
- no delta
## Evidence
- one finding
## Outcome
- still blocked
## Next
- keep watching
EOF
set +e
bash scripts/review/review_action_guard.sh "$BAD_REPORT" >/tmp/review_action_bad.out 2>&1
BAD_RC=$?
set -e
[[ "$BAD_RC" -ne 0 ]]
grep -q 'missing actionable next step' /tmp/review_action_bad.out
GOOD_REPORT="$TMP_DIR/good-review.md"
cat > "$GOOD_REPORT" <<'EOF'
## Context
- no delta
## Evidence
- one finding
## Outcome
- still blocked
## Next
- 处理问题 11新增 review action guard 并接入 review 生成链
EOF
bash scripts/review/review_action_guard.sh "$GOOD_REPORT" >/tmp/review_action_good.out 2>&1

View File

@@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$ROOT_DIR"
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT
cat > "$TMP_DIR/git_status.txt" <<'EOF'
EOF
cat > "$TMP_DIR/backlog_rows.txt" <<'EOF'
| 18 | no delta aging | P2 | 05-12 22:46 | ❌ 未修复 | 7 次 |
| 14 | phase6plus undefined | P1 | 05-10 21:30 | ❌ 未修复 | 6 次 |
| 15 | review false positive | P1 | 05-11 14:30 | ❌ 未修复 | 10 次 |
EOF
OUTPUT="$(bash scripts/review/review_status_summary.sh "$TMP_DIR/git_status.txt" "$TMP_DIR/backlog_rows.txt")"
printf '%s' "$OUTPUT" | grep -q 'aging_focus=14:P1:6,15:P1:10,18:P2:7'

View File

@@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$ROOT_DIR"
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT
cat > "$TMP_DIR/git_status.txt" <<'EOF'
EOF
cat > "$TMP_DIR/backlog_rows.txt" <<'EOF'
| 31 | no decision delta | P2 | 05-17 15:10 | ❌ 未修复 | 3 次 |
| 30 | aged precondition | P1 | 05-17 09:31 | ❌ 未修复 | 6 次 |
EOF
set +e
OUTPUT="$(bash scripts/review/review_status_summary.sh "$TMP_DIR/git_status.txt" "$TMP_DIR/backlog_rows.txt")"
set -e
printf '%s' "$OUTPUT" | grep -q 'same_day_no_decision_focus='
printf '%s' "$OUTPUT" | grep -q 'same_day_no_decision_focus=30:P1:6,31:P2:3'

View File

@@ -0,0 +1,69 @@
#!/usr/bin/env bash
set -euo pipefail
GIT_STATUS_PATH="${1:?git status file required}"
BACKLOG_ROWS_PATH="${2:?backlog rows file required}"
DIRTY_WORKTREE=0
if [[ -s "$GIT_STATUS_PATH" ]]; then
DIRTY_WORKTREE=1
fi
OPEN_ISSUES=$(grep -c '^|' "$BACKLOG_ROWS_PATH" || true)
NO_DELTA=true
FOCUS="risk_aging,unverified,backlog"
AGING_FOCUS="$(python3 - <<'PY' "$BACKLOG_ROWS_PATH"
from pathlib import Path
import sys
rows=[]
for line in Path(sys.argv[1]).read_text(encoding='utf-8').splitlines():
if not line.startswith('|'):
continue
parts=[p.strip() for p in line.strip('|').split('|')]
if len(parts) < 6:
continue
issue_id=parts[0]
priority=parts[2]
first_exposed=parts[3]
impact=parts[5].replace('次','').strip()
try:
impact_num=int(''.join(ch for ch in impact if ch.isdigit()) or '0')
except ValueError:
impact_num=0
rows.append((priority, first_exposed, -impact_num, issue_id, impact_num))
priority_rank={'P0':0,'P1':1,'P2':2}
rows.sort(key=lambda x:(priority_rank.get(x[0],9), x[1], x[2], x[3]))
focus=[]
for priority, first_exposed, neg_impact, issue_id, impact_num in rows[:3]:
focus.append(f"{issue_id}:{priority}:{impact_num}")
print(','.join(focus))
PY
)"
SAME_DAY_NO_DECISION_FOCUS="$(python3 - <<'PY' "$BACKLOG_ROWS_PATH"
from pathlib import Path
import sys
rows=[]
for line in Path(sys.argv[1]).read_text(encoding='utf-8').splitlines():
if not line.startswith('|'):
continue
parts=[p.strip() for p in line.strip('|').split('|')]
if len(parts) < 6:
continue
issue_id=parts[0]
priority=parts[2]
impact=parts[5].replace('次','').strip()
try:
impact_num=int(''.join(ch for ch in impact if ch.isdigit()) or '0')
except ValueError:
impact_num=0
rows.append((priority, -impact_num, issue_id, impact_num))
priority_rank={'P0':0,'P1':1,'P2':2}
rows.sort(key=lambda x:(priority_rank.get(x[0],9), x[1], x[2]))
focus=[]
for priority, neg_impact, issue_id, impact_num in rows[:2]:
focus.append(f"{issue_id}:{priority}:{impact_num}")
print(','.join(focus))
PY
)"
printf 'REVIEW_STATUS no_delta=%s dirty_worktree=%d open_issues=%d focus=%s aging_focus=%s same_day_no_decision_focus=%s\n' "$NO_DELTA" "$DIRTY_WORKTREE" "$OPEN_ISSUES" "$FOCUS" "$AGING_FOCUS" "$SAME_DAY_NO_DECISION_FOCUS"

View File

@@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$ROOT_DIR"
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT
cat > "$TMP_DIR/git_status.txt" <<'EOF'
EOF
cat > "$TMP_DIR/backlog_rows.txt" <<'EOF'
| 8 | cron review 无 delta 时空转 | P1 | 05-08 09:12 | ❌ 未修复 | 13 次 |
| 9 | 验证模式伪进展artifact_present 局限) | P1 | 05-08 14:30 | ❌ 未修复 | 10 次 |
EOF
OUTPUT="$(bash scripts/review/review_status_summary.sh "$TMP_DIR/git_status.txt" "$TMP_DIR/backlog_rows.txt")"
printf '%s' "$OUTPUT" | grep -q 'REVIEW_STATUS no_delta=true'
printf '%s' "$OUTPUT" | grep -q 'dirty_worktree=0'
printf '%s' "$OUTPUT" | grep -q 'open_issues=2'
printf '%s' "$OUTPUT" | grep -q 'focus=risk_aging,unverified,backlog'

View File

@@ -0,0 +1,24 @@
#!/usr/bin/env bash
set -euo pipefail
REPORT_PATH="${1:?review report path required}"
CONTENT="$(cat "$REPORT_PATH")"
if [[ "$CONTENT" != *'runtime-verified'* ]]; then
echo "missing truth label: runtime-verified" >&2
exit 1
fi
if [[ "$CONTENT" != *'current status'* && "$CONTENT" != *'当前状态'* ]]; then
echo "missing truth label: current status" >&2
exit 1
fi
if [[ "$CONTENT" == *'历史状态'* || "$CONTENT" == *'historical status'* || "$CONTENT" == *'历史 review'* || "$CONTENT" == *'上一轮 review'* ]]; then
if [[ "$CONTENT" != *'历史状态'* && "$CONTENT" != *'historical status'* ]]; then
echo "missing truth label: historical status" >&2
exit 1
fi
fi
echo "REVIEW_TRUTH_GUARD: PASS"

View File

@@ -0,0 +1,62 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$ROOT_DIR"
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT
BAD_REPORT="$TMP_DIR/bad-review.md"
cat > "$BAD_REPORT" <<'EOF'
## Evidence
### Incomplete
- 未完成项:外部文档源仍不稳定
- 当前状态:已经恢复绿色
EOF
set +e
bash scripts/review/review_truth_guard.sh "$BAD_REPORT" >/tmp/review_truth_bad.out 2>&1
BAD_RC=$?
set -e
[[ "$BAD_RC" -ne 0 ]]
grep -q 'missing truth label' /tmp/review_truth_bad.out
GOOD_REPORT="$TMP_DIR/good-review.md"
cat > "$GOOD_REPORT" <<'EOF'
## Evidence
### Incomplete
- 未完成项:外部文档源仍不稳定
- 当前状态:`runtime-verified`;最近一轮 `verify_phase6.sh` 已通过,但此条仅代表当前快照,不代表历史报告中的旧 FAIL 仍然成立。
EOF
bash scripts/review/review_truth_guard.sh "$GOOD_REPORT" >/tmp/review_truth_good.out 2>&1
DRIFT_REPORT="$TMP_DIR/drift-review.md"
cat > "$DRIFT_REPORT" <<'EOF'
## Evidence
### Inconsistencies
- 伪进展或文档/实现不一致项:历史 review 仍保留旧 FAIL
- 证据:上一轮 review 写了 FAIL
- 当前状态:`runtime-verified`;当前 verify_phase6 已通过
EOF
set +e
bash scripts/review/review_truth_guard.sh "$DRIFT_REPORT" >/tmp/review_truth_drift.out 2>&1
DRIFT_RC=$?
set -e
[[ "$DRIFT_RC" -ne 0 ]]
grep -q 'missing truth label: historical status' /tmp/review_truth_drift.out
GOOD_DRIFT_REPORT="$TMP_DIR/good-drift-review.md"
cat > "$GOOD_DRIFT_REPORT" <<'EOF'
## Evidence
### Inconsistencies
- 伪进展或文档/实现不一致项:历史 review 仍保留旧 FAIL
- 历史状态:上一轮 review 记录为 FAIL
- 当前状态:`runtime-verified`;当前 verify_phase6 已通过
EOF
bash scripts/review/review_truth_guard.sh "$GOOD_DRIFT_REPORT" >/tmp/review_truth_good_drift.out 2>&1
grep -q 'REVIEW_TRUTH_GUARD: PASS' /tmp/review_truth_good_drift.out
grep -q 'REVIEW_TRUTH_GUARD: PASS' /tmp/review_truth_good.out

View File

@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -euo pipefail
STATUS_FILE="${1:?status file required}"
LINE="$(cat "$STATUS_FILE")"
for token in tracked_modified= untracked= total=; do
if [[ "$LINE" != *"$token"* ]]; then
echo "missing tracked_modified/untracked counters" >&2
exit 1
fi
done
echo "REVIEW_WORKTREE_GUARD: PASS"

View File

@@ -0,0 +1,23 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$ROOT_DIR"
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT
BAD_FILE="$TMP_DIR/bad-worktree.txt"
printf 'WORKTREE_STATUS label=cron state=dirty commit_hint=needed\n' > "$BAD_FILE"
set +e
bash scripts/review/review_worktree_status_guard.sh "$BAD_FILE" >/tmp/review_worktree_bad.out 2>&1
BAD_RC=$?
set -e
[[ "$BAD_RC" -ne 0 ]]
grep -q 'missing tracked_modified/untracked counters' /tmp/review_worktree_bad.out
GOOD_FILE="$TMP_DIR/good-worktree.txt"
printf 'WORKTREE_STATUS label=cron state=dirty tracked_modified=2 untracked=3 total=5 commit_hint=needed\n' > "$GOOD_FILE"
bash scripts/review/review_worktree_status_guard.sh "$GOOD_FILE" >/tmp/review_worktree_good.out 2>&1
grep -q 'REVIEW_WORKTREE_GUARD: PASS' /tmp/review_worktree_good.out

View File

@@ -0,0 +1,11 @@
#!/usr/bin/env bash
set -euo pipefail
STATUS_FILE="${1:?phase status file required}"
if ! grep -q '^ROOT_CAUSE class=' "$STATUS_FILE"; then
echo "missing root cause summary" >&2
exit 1
fi
echo "ROOT_CAUSE_GUARD: PASS"

View File

@@ -0,0 +1,34 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$ROOT_DIR"
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT
BAD_FILE="$TMP_DIR/bad-phase6.txt"
cat > "$BAD_FILE" <<'EOF'
[FAIL] importer_smoke_gate_result=FAIL 新增导入器 smoke gate 未通过
[FAIL] live_run_result=FAIL 主链路真实采集失败
SUMMARY pass=10 fail=2 warn=0
PHASE_RESULT: FAIL
EOF
set +e
bash scripts/review/root_cause_summary_guard.sh "$BAD_FILE" >/tmp/root_cause_bad.out 2>&1
BAD_RC=$?
set -e
[[ "$BAD_RC" -ne 0 ]]
grep -q 'missing root cause summary' /tmp/root_cause_bad.out
GOOD_FILE="$TMP_DIR/good-phase6.txt"
cat > "$GOOD_FILE" <<'EOF'
[FAIL] importer_smoke_gate_result=FAIL 新增导入器 smoke gate 未通过
ROOT_CAUSE class=importer_smoke_gate_failure source=importer_smoke_gate summary=新增导入器 smoke gate 未通过
SUMMARY pass=10 fail=1 warn=0
PHASE_RESULT: FAIL
EOF
bash scripts/review/root_cause_summary_guard.sh "$GOOD_FILE" >/tmp/root_cause_good.out 2>&1
grep -q 'ROOT_CAUSE_GUARD: PASS' /tmp/root_cause_good.out

View File

@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -euo pipefail
STATUS_FILE="${1:?status file required}"
LINE="$(cat "$STATUS_FILE")"
if [[ "$LINE" == *"external_provider_failure="* ]]; then
if [[ "$LINE" != *"stability_label="* ]]; then
echo "missing stability label" >&2
exit 1
fi
fi
echo "STABILITY_STATUS_GUARD: PASS"

View File

@@ -0,0 +1,28 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$ROOT_DIR"
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT
BAD_FILE="$TMP_DIR/bad-status.txt"
cat > "$BAD_FILE" <<'EOF'
window_size=7 success_count=6 failure_count=1 success_rate=85.71 threshold=95 precondition_missing=0 external_provider_failure=1 collector_runtime_failure=0 unknown_failure=0
EOF
set +e
bash scripts/review/stability_status_guard.sh "$BAD_FILE" >/tmp/stability_bad.out 2>&1
BAD_RC=$?
set -e
[[ "$BAD_RC" -ne 0 ]]
grep -q 'missing stability label' /tmp/stability_bad.out
GOOD_FILE="$TMP_DIR/good-status.txt"
cat > "$GOOD_FILE" <<'EOF'
window_size=7 success_count=6 failure_count=1 success_rate=85.71 threshold=95 precondition_missing=0 external_provider_failure=1 collector_runtime_failure=0 unknown_failure=0 stability_label=recovered-external-incident
EOF
bash scripts/review/stability_status_guard.sh "$GOOD_FILE" >/tmp/stability_good.out 2>&1
grep -q 'STABILITY_STATUS_GUARD: PASS' /tmp/stability_good.out

View File

@@ -0,0 +1,29 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$ROOT_DIR"
PROJECT_TASKS="$ROOT_DIR/TASKS.md"
PROJECT_GOALS="$ROOT_DIR/GOALS.md"
GLOBAL_TASKS="/home/long/.openclaw/workspace/TASKS.md"
GLOBAL_GOALS="/home/long/.openclaw/workspace/GOALS.md"
bash scripts/review/preflight_task_write_guard.sh llm-intelligence-agent "$PROJECT_TASKS" "$PROJECT_GOALS" >/dev/null
set +e
bash scripts/review/preflight_task_write_guard.sh llm-intelligence-agent "$GLOBAL_TASKS" >/tmp/llm_subagent_guard.err 2>&1
RC1=$?
set -e
[[ "$RC1" -ne 0 ]]
grep -Eq 'shared workspace file|forbidden' /tmp/llm_subagent_guard.err
set +e
bash scripts/review/preflight_task_write_guard.sh llm-intelligence-agent "$GLOBAL_GOALS" >/tmp/llm_subagent_guard_goal.err 2>&1
RC2=$?
set -e
[[ "$RC2" -ne 0 ]]
grep -Eq 'shared workspace file|forbidden' /tmp/llm_subagent_guard_goal.err
echo "subagent_workspace_guard_test: PASS"