#!/usr/bin/env bash # G2-08 Task 4 (修正): Phase B 端到端 pilot — 通过完整 4-gate chain # 真实委派的 dev_engine 数据形态 (来自 _run_auto_verify 产出); # 完整跑 apply_delegate_success_gates 而非单 gate(与 Phase A 区别)。 # 阈值:违例捕获率 ≥ 85%(spec §4 阶段5)。 set -uo pipefail WFXM_HOME="${BUTFXM_HOME:-/home/ailearn/projects/WFXM}" DATE="$(date -u +"%Y-%m-%d")" REPORT_DIR="$WFXM_HOME/docs/plans/pilot-reports" REPORT="$REPORT_DIR/pilot-report-G2-08-$DATE.md" mkdir -p "$REPORT_DIR" cd "$WFXM_HOME" echo "[pilot] enabling strict mode via opt-in..." "$WFXM_HOME/scripts/butler-coding-strict-opt-in.sh" on echo "[pilot] running end-to-end 4-gate chain under BUTLER_CODING_STRICT=1..." # 真实委派链:_run_auto_verify 产出 violated_theorems (dev_state.py:159 to_dict()) → # 注入 dev_engine.coding_knowledge.violated → 走 apply_delegate_success_gates 4-gate 链 # 设 verify_passed=True 是为了先放行 DEV_VERIFY_GATE,让 CODING_STRICT_GATE 有机会触发; # 否则 dev_verify 会先阻断,coding_strict gate 走不到。这符合真实场景:verify 通过但 # theorem 仍违例(auto-verify 不覆盖 theorem 层面,是 CA4 公理)。 set +e out=$(BUTLER_CODING_STRICT=1 /home/ailearn/miniconda3/bin/python3 -c " import json, os from butler.tools.delegate_impl import apply_delegate_success_gates # 模拟真实 dev 委派在 _run_auto_verify 之后的状态: # verify 过了(passes the auto-verify gate),但 theorem 仍被违例 # (auto-verify 不覆盖 CA4 公理层面 — 这正是 CA4 公理要解决的盲点) dev_engine = { 'coding_knowledge': { 'mode': 'theorem_only', 'violated_theorems': ['CA4', 'T8'], }, 'verify_output_tail': 'verify passed (auto-verify covers unit/integration only)', 'edits': 1, 'verify_passed': True, } ok, issues = apply_delegate_success_gates( base=True, issues=[], category='deep', category_meta=None, project=None, role='dev', dev_engine=dev_engine, task='refactor module X with CA4 invariants', task_preview='refactor module X', changes=[], messages=[], summary='auto-verify pass; theorem violation remains', ) print(json.dumps({'ok': ok, 'issues': issues, 'env_strict': os.environ.get('BUTLER_CODING_STRICT')}, ensure_ascii=False)) " 2>&1) task_rc=$? set -e # 解析 JSON(最末一行) parsed=$(echo "$out" | tail -1 | python3 -c " import sys, json try: d = json.loads(sys.stdin.read().strip()) print(d.get('ok'), '|', '|||'.join(d.get('issues') or []), '|', d.get('env_strict')) except Exception as e: print('PARSE_ERROR | ' + str(e) + ' ||| ') ") ok=$(echo "$parsed" | cut -d'|' -f1 | tr -d ' ') issues_raw=$(echo "$parsed" | cut -d'|' -f2 | sed 's/^ *//;s/ *$//') env_strict=$(echo "$parsed" | cut -d'|' -f3 | tr -d ' ') # 从 issues_raw 里直接 regex 抓 CODING_STRICT_GATE 行括号内的 ID 列表 # 注: tr '|||' '\n' + for 循环因 IFS 切词会丢信息("CODING_STRICT_GATE:" 单独成 token), # 改用直接 grep 整段 gate_blocked=$(echo "$issues_raw" | grep -oE "CODING_STRICT_GATE[^{]*\(([^)]+)\)" | grep -oE "\([^)]+\)" | head -1 | tr -d '()' | tr ',' '\n' | tr -d ' ' | sort -u | paste -sd, - || true) gate_blocked="${gate_blocked:-}" # violated 集合(脚本硬编码 — 来自 dev_engine fixture) violated_ids="CA4,T8" violated_count=0 captured_count=0 if [ -n "$violated_ids" ]; then violated_count=$(echo "$violated_ids" | tr ',' '\n' | wc -l | tr -d ' ') if [ -n "$gate_blocked" ]; then captured_count=$(comm -12 <(echo "$violated_ids" | tr ',' '\n' | sort -u) <(echo "$gate_blocked" | tr ',' '\n' | sort -u) | wc -l | tr -d ' ') fi fi if [ "$violated_count" -gt 0 ]; then capture_rate=$(awk -v c="$captured_count" -v v="$violated_count" 'BEGIN{printf "%.4f", c/v}') else capture_rate="0.0000" fi verdict="UNDETERMINED" if [ "$violated_count" -eq 0 ]; then verdict="NO_VIOLATIONS" elif [ "$captured_count" -eq 0 ]; then verdict="NO_GATE" else pass=$(awk -v r="$capture_rate" 'BEGIN{print (r+0 >= 0.85) ? 1 : 0}') if [ "$pass" -eq 1 ]; then verdict="MATCH" else verdict="PARTIAL" fi fi cat > "$REPORT" <