fix: harden review and verifier governance
This commit is contained in:
37
scripts/review/backlog_blocker_freshness_guard.sh
Executable file
37
scripts/review/backlog_blocker_freshness_guard.sh
Executable 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
|
||||
41
scripts/review/backlog_blocker_freshness_guard_test.sh
Normal file
41
scripts/review/backlog_blocker_freshness_guard_test.sh
Normal 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:10(afternoon-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:10(afternoon-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
|
||||
25
scripts/review/backlog_current_freshness_guard.sh
Executable file
25
scripts/review/backlog_current_freshness_guard.sh
Executable 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
|
||||
36
scripts/review/backlog_current_freshness_guard_test.sh
Normal file
36
scripts/review/backlog_current_freshness_guard_test.sh
Normal 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
|
||||
28
scripts/review/backlog_current_table_guard.sh
Executable file
28
scripts/review/backlog_current_table_guard.sh
Executable 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
|
||||
38
scripts/review/backlog_current_table_guard_test.sh
Normal file
38
scripts/review/backlog_current_table_guard_test.sh
Normal 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
|
||||
31
scripts/review/backlog_revocation_guard.sh
Executable file
31
scripts/review/backlog_revocation_guard.sh
Executable 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
|
||||
40
scripts/review/backlog_revocation_guard_test.sh
Normal file
40
scripts/review/backlog_revocation_guard_test.sh
Normal 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
|
||||
14
scripts/review/blocker_switch_guard.sh
Executable file
14
scripts/review/blocker_switch_guard.sh
Executable 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"
|
||||
31
scripts/review/blocker_switch_guard_test.sh
Normal file
31
scripts/review/blocker_switch_guard_test.sh
Normal 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:10(afternoon-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:10(afternoon-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
|
||||
12
scripts/review/current_row_revocation_guard.sh
Executable file
12
scripts/review/current_row_revocation_guard.sh
Executable 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"
|
||||
12
scripts/review/global_blocker_switch_capture_test.sh
Normal file
12
scripts/review/global_blocker_switch_capture_test.sh
Normal 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"
|
||||
20
scripts/review/global_blocker_switch_guard.sh
Executable file
20
scripts/review/global_blocker_switch_guard.sh
Executable 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"
|
||||
33
scripts/review/global_blocker_switch_guard_test.sh
Normal file
33
scripts/review/global_blocker_switch_guard_test.sh
Normal 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
|
||||
23
scripts/review/live_run_classification_test.sh
Normal file
23
scripts/review/live_run_classification_test.sh
Normal 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' ]]
|
||||
12
scripts/review/partial_output_guard.sh
Executable file
12
scripts/review/partial_output_guard.sh
Executable 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"
|
||||
30
scripts/review/partial_output_guard_test.sh
Normal file
30
scripts/review/partial_output_guard_test.sh
Normal 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
|
||||
20
scripts/review/provider_root_cause_test.sh
Normal file
20
scripts/review/provider_root_cause_test.sh
Normal 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' ]]
|
||||
12
scripts/review/release_semantics_capture_test.sh
Normal file
12
scripts/review/release_semantics_capture_test.sh
Normal 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"
|
||||
11
scripts/review/release_semantics_guard.sh
Executable file
11
scripts/review/release_semantics_guard.sh
Executable 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"
|
||||
29
scripts/review/release_semantics_guard_test.sh
Normal file
29
scripts/review/release_semantics_guard_test.sh
Normal 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_only;stability_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_only;stability_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
|
||||
35
scripts/review/review_action_guard.sh
Executable file
35
scripts/review/review_action_guard.sh
Executable 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"
|
||||
47
scripts/review/review_action_guard_test.sh
Normal file
47
scripts/review/review_action_guard_test.sh
Normal 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
|
||||
20
scripts/review/review_aging_priority_test.sh
Normal file
20
scripts/review/review_aging_priority_test.sh
Normal 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'
|
||||
22
scripts/review/review_same_day_no_decision_test.sh
Normal file
22
scripts/review/review_same_day_no_decision_test.sh
Normal 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'
|
||||
69
scripts/review/review_status_summary.sh
Executable file
69
scripts/review/review_status_summary.sh
Executable 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"
|
||||
22
scripts/review/review_status_summary_test.sh
Normal file
22
scripts/review/review_status_summary_test.sh
Normal 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'
|
||||
24
scripts/review/review_truth_guard.sh
Executable file
24
scripts/review/review_truth_guard.sh
Executable 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"
|
||||
62
scripts/review/review_truth_guard_test.sh
Normal file
62
scripts/review/review_truth_guard_test.sh
Normal 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
|
||||
14
scripts/review/review_worktree_status_guard.sh
Executable file
14
scripts/review/review_worktree_status_guard.sh
Executable 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"
|
||||
23
scripts/review/review_worktree_status_guard_test.sh
Normal file
23
scripts/review/review_worktree_status_guard_test.sh
Normal 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
|
||||
11
scripts/review/root_cause_summary_guard.sh
Executable file
11
scripts/review/root_cause_summary_guard.sh
Executable 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"
|
||||
34
scripts/review/root_cause_summary_test.sh
Normal file
34
scripts/review/root_cause_summary_test.sh
Normal 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
|
||||
14
scripts/review/stability_status_guard.sh
Executable file
14
scripts/review/stability_status_guard.sh
Executable 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"
|
||||
28
scripts/review/stability_status_guard_test.sh
Normal file
28
scripts/review/stability_status_guard_test.sh
Normal 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
|
||||
29
scripts/review/subagent_workspace_guard_test.sh
Normal file
29
scripts/review/subagent_workspace_guard_test.sh
Normal 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"
|
||||
Reference in New Issue
Block a user