#!/bin/bash
# 사용법: finish-task.sh <task_id> [team_short] [project_path]
# L1 마무리 스크립트: QC → 머지 → .done 생성 → task-timer end → notify-completion
set -euo pipefail
TASK_ID="$1"
TEAM_SHORT="${2:-""}"
PROJECT_PATH="${3:-""}"
WORKSPACE="/home/jay/workspace"
EVENTS_DIR="$WORKSPACE/memory/events"
DONE_FILE="$EVENTS_DIR/${TASK_ID}.done"

# team_short 미지정 시 task-timers.json에서 자동 추출
if [ -z "$TEAM_SHORT" ]; then
    TEAM_SHORT=$(python3 -c "
import json
try:
    with open('$WORKSPACE/memory/task-timers.json') as f:
        data = json.load(f)
    tasks = data.get('tasks', data)
    t = tasks.get('$TASK_ID', {})
    print(t.get('team', ''))
except Exception:
    print('')
" 2>/dev/null || echo "")
fi

# 0. 노하우 업데이트 검증 (디자인/마케팅 작업만)
TASK_FILE="$WORKSPACE/memory/tasks/${TASK_ID}.md"
if [ -f "$TASK_FILE" ]; then
    # task 파일에 디자인/마케팅 키워드가 있는지 확인
    if grep -qiE "디자인|배너|이미지|banner|image|광고|마케팅|카피|copywriting" "$TASK_FILE" 2>/dev/null; then
        # task-timer에서 start_time 가져오기
        TASK_START=$(python3 -c "
import json
with open('$WORKSPACE/memory/task-timers.json') as f:
    data = json.load(f)
tasks = data.get('tasks', data)
t = tasks.get('$TASK_ID', {})
print(t.get('start_time', ''))
" 2>/dev/null || echo "")

        if [ -n "$TASK_START" ]; then
            # 노하우 파일들의 수정 시간이 작업 시작 이후인지 확인
            KNOWHOW_CHECK=$(python3 -c "
import os, sys
from datetime import datetime

start_str = '$TASK_START'
start_time = datetime.fromisoformat(start_str)

knowhow_files = [
    '$WORKSPACE/memory/specs/knowhow-design.md',
    '$WORKSPACE/memory/specs/design-qc-knowhow.md',
    '$WORKSPACE/memory/specs/knowhow-marketing.md',
]

updated = []
for f in knowhow_files:
    if os.path.exists(f):
        mtime = datetime.fromtimestamp(os.path.getmtime(f))
        if mtime > start_time:
            updated.append(os.path.basename(f))

if not updated:
    print('FAIL')
    print('노하우 파일이 작업 시작 이후 업데이트되지 않았습니다.', file=sys.stderr)
    print(f'작업 시작: {start_str}', file=sys.stderr)
    for f in knowhow_files:
        if os.path.exists(f):
            mtime = datetime.fromtimestamp(os.path.getmtime(f)).isoformat()
            print(f'  {os.path.basename(f)}: {mtime}', file=sys.stderr)
else:
    print('PASS')
" 2>/dev/null)

            if [ "$KNOWHOW_CHECK" = "FAIL" ]; then
                echo "[ERROR] ❌ 노하우 파일 업데이트 미확인. .done 생성 차단."
                echo "[ERROR] 디자인/마케팅 QC 후에는 반드시 노하우 파일을 업데이트해야 합니다."
                echo "[ERROR] 대상: knowhow-design.md, design-qc-knowhow.md, knowhow-marketing.md 중 최소 1개"
                echo "[HINT] --skip-knowhow-check 환경변수로 우회 가능: SKIP_KNOWHOW_CHECK=1 bash finish-task.sh $TASK_ID"
                if [ "${SKIP_KNOWHOW_CHECK:-0}" != "1" ]; then
                    exit 1
                fi
                echo "[WARN] SKIP_KNOWHOW_CHECK=1로 우회합니다."
            fi
        fi
    fi
fi

# 0b. QC 프로세스 검증 (디자인/이미지 작업만)
REPORT_FILE="$WORKSPACE/memory/reports/${TASK_ID}.md"
if [ -f "$TASK_FILE" ]; then
    if grep -qiE "디자인|배너|이미지|banner|image|광고|마케팅|카피|copywriting" "$TASK_FILE" 2>/dev/null; then
        if [ ! -f "$REPORT_FILE" ]; then
            echo "[WARN] ⚠️ 보고서 파일 없음: $REPORT_FILE — QC 프로세스 검증을 건너뜁니다."
        else
            # 검증 2: 로키 소환 검증
            if [ "${SKIP_LOKI_CHECK:-0}" != "1" ]; then
                LOKI_CHECK=$(python3 -c "
import re, sys
report_path = '$REPORT_FILE'
try:
    with open(report_path) as f:
        content = f.read()
    model_section = re.search(r'## 모델 사용 기록.*?(?=\n## |\Z)', content, re.DOTALL)
    if model_section:
        section_text = model_section.group()
        has_loki_opus = bool(re.search(r'로키|Loki', section_text)) and bool(re.search(r'opus', section_text))
        if not has_loki_opus:
            print('FAIL')
        else:
            print('PASS')
    else:
        print('FAIL')
except Exception as e:
    print('FAIL', file=sys.stderr)
    print('FAIL')
" 2>/dev/null || echo "FAIL")
                if [ "$LOKI_CHECK" = "FAIL" ]; then
                    echo "[ERROR] ❌ 디자인 QC에 로키(opus) 참여 기록 없음."
                    echo "[ERROR] 디자인 QC는 로키(opus) 단독 필수. 팀장 자체 평가는 규칙 위반."
                    exit 1
                fi
            else
                echo "[WARN] ⚠️ SKIP_LOKI_CHECK=1 — 로키 소환 체크를 우회합니다."
            fi

            # 검증 3: "팀장 시각 검수" 패턴 차단 (WARNING만)
            if grep -qiE "팀장 시각 검수|팀장 검수|팀장 판단|자체 평가" "$REPORT_FILE" 2>/dev/null; then
                echo "[WARN] ⚠️ \"팀장 시각 검수\" 패턴 감지. 디자인 QC는 로키(opus)만 수행 가능."
            fi
        fi
    fi
fi

# 1. QC 실행 (멱등성: .qc-done 이미 있으면 스킵)
QC_RESULT_FILE="$EVENTS_DIR/${TASK_ID}.qc-result"
QC_DONE_FILE="$EVENTS_DIR/${TASK_ID}.qc-done"

if [ -f "$QC_DONE_FILE" ]; then
    echo "[INFO] .qc-done 이미 존재 — QC 단계 스킵."
else
    # 팀별 qc_verify.py 경로 결정
    if [ -n "$TEAM_SHORT" ] && [ -f "$WORKSPACE/teams/${TEAM_SHORT}/qc/qc_verify.py" ]; then
        QC_SCRIPT="$WORKSPACE/teams/${TEAM_SHORT}/qc/qc_verify.py"
    else
        QC_SCRIPT="$WORKSPACE/teams/shared/qc_verify.py"
    fi

    echo "[INFO] QC 실행: $QC_SCRIPT --gate --task-id $TASK_ID"
    if [ -n "$TEAM_SHORT" ]; then
        python3 "$QC_SCRIPT" --gate --task-id "$TASK_ID" --team "$TEAM_SHORT" 2>&1 || true
    else
        python3 "$QC_SCRIPT" --gate --task-id "$TASK_ID" 2>&1 || true
    fi

    # QC 결과 확인
    if [ ! -f "$QC_RESULT_FILE" ]; then
        echo "[ERROR] QC 실행 후 .qc-result 파일이 생성되지 않았습니다: $QC_RESULT_FILE"
        exit 1
    fi

    QC_STATUS=$(python3 -c "
import json, sys
try:
    with open('$QC_RESULT_FILE') as f:
        data = json.load(f)
    print(data.get('qc_result', 'FAIL'))
except Exception:
    print('FAIL')
" 2>/dev/null || echo "FAIL")

    if [ "$QC_STATUS" = "FAIL" ]; then
        # QC FAIL 시 .failed 이벤트 생성
        FAILED_FILE="$EVENTS_DIR/${TASK_ID}.failed"
        echo '{"task_id":"'"$TASK_ID"'","team":"'"$TEAM_SHORT"'","fail_reason":"QC FAIL","timestamp":"'"$(date -Iseconds)"'"}' > "$FAILED_FILE"
        echo "[FAIL] QC FAIL — .failed 생성: $FAILED_FILE"
        exit 1
    fi

    # QC 완료 표시
    echo '{"task_id":"'"$TASK_ID"'","qc_result":"'"$QC_STATUS"'","timestamp":"'"$(date -Iseconds)"'"}' > "$QC_DONE_FILE"
    echo "[INFO] QC $QC_STATUS — .qc-done 생성: $QC_DONE_FILE"
fi

# QC 결과 읽기 (후속 단계용)
QC_STATUS=$(python3 -c "
import json, sys
try:
    with open('$QC_RESULT_FILE') as f:
        data = json.load(f)
    print(data.get('qc_result', 'PASS'))
except Exception:
    print('PASS')
" 2>/dev/null || echo "PASS")

# 2. 머지 (멱등성: .merge-done 이미 있으면 스킵, project_path 없으면 스킵)
MERGE_DONE_FILE="$EVENTS_DIR/${TASK_ID}.merge-done"

if [ -f "$MERGE_DONE_FILE" ]; then
    echo "[INFO] .merge-done 이미 존재 — 머지 단계 스킵."
elif [ -z "$PROJECT_PATH" ]; then
    echo "[INFO] PROJECT_PATH 미지정 — 머지 단계 스킵 (시스템 작업)."
else
    echo "[INFO] 머지 실행: worktree_manager.py finish $PROJECT_PATH $TASK_ID $TEAM_SHORT --action auto"
    python3 "$WORKSPACE/scripts/worktree_manager.py" finish "$PROJECT_PATH" "$TASK_ID" "$TEAM_SHORT" --action auto 2>&1 || {
        echo "[WARN] worktree_manager.py finish 실패 — 계속 진행."
    }
    echo '{"task_id":"'"$TASK_ID"'","project_path":"'"$PROJECT_PATH"'","timestamp":"'"$(date -Iseconds)"'"}' > "$MERGE_DONE_FILE"
    echo "[INFO] 머지 완료 — .merge-done 생성: $MERGE_DONE_FILE"
fi

# 2.5. Git 커밋 검증 게이트 (task-2031)
# non-code task 판별: 코드 수정 없는 작업은 git 게이트 SKIP
GIT_GATE_SKIP=0
if [ -f "$TASK_FILE" ]; then
    # ## 레벨 섹션 내에서만 non-code 키워드를 검사 (본문의 설명 텍스트 오탐 방지)
    GIT_GATE_SKIP=$(python3 -c "
import re, sys
try:
    with open('$TASK_FILE', encoding='utf-8') as f:
        content = f.read()
    # ## 레벨 섹션 추출
    m = re.search(r'## 레벨\s*\n(.*?)(?=\n## |\Z)', content, re.DOTALL)
    if m:
        section = m.group(1)
        if re.search(r'코드 수정 없음|문서 업데이트만|문서만|리서치만', section):
            print('1')
        else:
            print('0')
    else:
        print('0')
except Exception:
    print('0')
" 2>/dev/null || echo "0")
    if [ "$GIT_GATE_SKIP" -eq 1 ]; then
        echo "[GIT-GATE] non-code task 감지 — git 검증 SKIP."
    fi
fi

# 변수 기본값 초기화 (Git 게이트 skip 시에도 후속 게이트가 참조 가능하도록)
PROJ_DIR="${PROJECT_PATH:-$WORKSPACE}"
COMMIT_COUNT=0

if [ "$GIT_GATE_SKIP" -eq 0 ]; then
    # 작업 디렉토리 기반 프로젝트 루트 감지
    WORK_DIR="${PROJECT_PATH:-$WORKSPACE}"
    PROJ_DIR=$(git -C "$WORK_DIR" rev-parse --show-toplevel 2>/dev/null || echo "$WORK_DIR")

    # 1) task ID 커밋 최소 1건
    COMMIT_COUNT=$(git -C "$PROJ_DIR" log --oneline --all --grep="$TASK_ID" 2>/dev/null | wc -l)
    if [ "$COMMIT_COUNT" -eq 0 ]; then
        echo "[GIT-GATE] BLOCKED: $TASK_ID 커밋 0건. git commit 후 재실행." >&2
        exit 1
    fi
    echo "[GIT-GATE] 커밋 $COMMIT_COUNT건 확인."

    # 2) uncommitted 변경 없음 (시스템 자동 파일 제외)
    REAL_DIFF=$(git -C "$PROJ_DIR" diff --name-only 2>/dev/null | { grep -v -E '(memory/heartbeats/|memory/events/|memory/daily/|memory/logs/|memory/reports/|memory/tasks/|logs/|whisper/|bot-activity\.json|token-ledger\.json|memory/pipeline-status\.json|memory/preview-state\.json|memory/merge-log\.json|memory/bot_settings_sync\.json|memory/memory-check-log\.json|dashboard/data/refine-|\.heartbeat|memory/\.task-counter|memory/task-timers\.json)' || true; } | wc -l)
    REAL_CACHED=$(git -C "$PROJ_DIR" diff --cached --name-only 2>/dev/null | { grep -v -E '(memory/heartbeats/|memory/events/|memory/daily/|memory/logs/|memory/reports/|memory/tasks/|logs/|whisper/|bot-activity\.json|token-ledger\.json|memory/pipeline-status\.json|memory/preview-state\.json|memory/merge-log\.json|memory/bot_settings_sync\.json|memory/memory-check-log\.json|dashboard/data/refine-|\.heartbeat|memory/\.task-counter|memory/task-timers\.json)' || true; } | wc -l)
    if [ "$REAL_DIFF" -gt 0 ] || [ "$REAL_CACHED" -gt 0 ]; then
        echo "[GIT-GATE] BLOCKED: uncommitted 변경 존재 (${REAL_DIFF} unstaged, ${REAL_CACHED} staged)." >&2
        exit 1
    fi
    echo "[GIT-GATE] uncommitted 변경 없음 확인 (시스템 자동 파일 제외)."

    # 3) 빈 커밋 방어
    LAST_HASH=$(git -C "$PROJ_DIR" log --all --grep="$TASK_ID" --format="%H" -1 2>/dev/null)
    if [ -n "$LAST_HASH" ]; then
        DIFF_FILES=$(git -C "$PROJ_DIR" diff --name-only "${LAST_HASH}^..${LAST_HASH}" 2>/dev/null | wc -l)
        if [ "$DIFF_FILES" -eq 0 ]; then
            echo "[GIT-GATE] BLOCKED: 빈 커밋(변경 파일 0건)." >&2
            exit 1
        fi
        echo "[GIT-GATE] 마지막 커밋 변경 파일 ${DIFF_FILES}건 확인."
    fi

    echo "[GIT-GATE] PASS — git 검증 통과."
fi

# 2.6. Impact Scanner Gate
IMPACT_RESULT_VAL="PASS"
IMPACT_ENABLED=$(python3 -c "from utils.gate_config_loader import is_gate_enabled; print(is_gate_enabled('impact_scanner'))" 2>/dev/null || echo "false")
if [ "$IMPACT_ENABLED" = "True" ]; then
    IMPACT_MODE=$(python3 -c "from utils.gate_config_loader import get_gate_mode; print(get_gate_mode('impact_scanner'))" 2>/dev/null || echo "warn")
    set +e
    IMPACT_RAW=$(python3 scripts/impact_scanner.py --project-root "$PROJ_DIR" --task-id "$TASK_ID" 2>/dev/null | tail -1)
    IMPACT_EXIT=$?
    set -e
    IMPACT_GATE=$(echo "$IMPACT_RAW" | python3 -c "import sys,json; print(json.load(sys.stdin).get('gate_result','PASS'))" 2>/dev/null || echo "PASS")
    if [ $IMPACT_EXIT -eq 2 ] || [ "$IMPACT_GATE" = "BLOCK" ]; then
        IMPACT_RESULT_VAL="BLOCK"
    elif [ $IMPACT_EXIT -eq 1 ] || [ "$IMPACT_GATE" = "WARN" ]; then
        IMPACT_RESULT_VAL="WARN"
    fi
    echo "[IMPACT-GATE] result=$IMPACT_RESULT_VAL mode=$IMPACT_MODE"
    if [ "$IMPACT_RESULT_VAL" = "BLOCK" ] && [ "$IMPACT_MODE" = "fail" ]; then
        echo "[IMPACT-GATE] BLOCKED: 수정되지 않은 참조 파일 6건 이상"
        exit 1
    fi
else
    echo "[IMPACT-GATE] disabled — 스킵."
fi

# 2.6.5. CI Preflight Gate
CI_RESULT_VAL="PASS"
CI_ENABLED=$(python3 -c "from utils.gate_config_loader import is_gate_enabled; print(is_gate_enabled('ci_preflight'))" 2>/dev/null || echo "false")
if [ "$CI_ENABLED" = "True" ]; then
    CI_MODE=$(python3 -c "from utils.gate_config_loader import get_gate_mode; print(get_gate_mode('ci_preflight'))" 2>/dev/null || echo "warn")
    set +e
    bash scripts/ci_preflight.sh "$PROJ_DIR" --affected-only "$COMMIT_COUNT"
    CI_EXIT=$?
    set -e
    if [ $CI_EXIT -eq 0 ]; then
        CI_RESULT_VAL="PASS"
    elif [ $CI_EXIT -eq 2 ]; then
        CI_RESULT_VAL="WARN"
    else
        CI_RESULT_VAL="FAIL"
    fi
    echo "[CI-PREFLIGHT] exit=$CI_EXIT result=$CI_RESULT_VAL mode=$CI_MODE"
    if [ "$CI_RESULT_VAL" = "FAIL" ] && [ "$CI_MODE" = "fail" ]; then
        echo "[CI-PREFLIGHT] BLOCKED: CI 테스트 실패"
        exit 1
    fi
else
    echo "[CI-PREFLIGHT] disabled — 스킵."
fi

# 2.7. 팀원 전원 idle 복원 (member-status.json)
python3 -c "
import json
from datetime import datetime, timezone
status_file = '$WORKSPACE/memory/events/member-status.json'
try:
    with open(status_file) as f:
        data = json.load(f)
    now = datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ')
    changed = False
    for name, info in data.get('members', {}).items():
        if info.get('status') in ('working', 'standby'):
            task_desc = info.get('task', '') or ''
            if '$TASK_ID' in task_desc or not task_desc or info.get('status') == 'standby':
                info['status'] = 'idle'
                info['since'] = now
                info['task'] = None
                changed = True
    if changed:
        data['updated_at'] = now
        with open(status_file, 'w') as f:
            json.dump(data, f, indent=2, ensure_ascii=False)
        print('[INFO] member-status.json: working/standby → idle 복원 완료')
    else:
        print('[INFO] member-status.json: 복원 대상 없음')
except Exception as e:
    print(f'[WARN] member-status idle 복원 실패: {e}')
" 2>&1 || echo "[WARN] member-status idle 복원 스킵"

# 2.8. G3 독립 검증 (Lv.3+ 작업에만 적용)
TASK_LEVEL=$(python3 -c "
import json, re
workspace = '$WORKSPACE'
task_id = '$TASK_ID'

# 1차: task-timers.json work_level
level = ''
try:
    with open(f'{workspace}/memory/task-timers.json') as f:
        data = json.load(f)
    tasks = data.get('tasks', data)
    t = tasks.get(task_id, {})
    level = (t.get('work_level', '') or '').strip().lower()
except Exception:
    pass

# 2차: task 파일 ## 레벨 섹션 파싱
if not level:
    task_file = f'{workspace}/memory/tasks/{task_id}.md'
    try:
        with open(task_file) as f:
            content = f.read()
        m = re.search(r'## 레벨\s*\n(.*?)(?=\n## |\Z)', content, re.DOTALL)
        if m:
            section = m.group(1).strip().lower()
            if 'critical' in section:
                level = 'critical'
            elif 'security' in section:
                level = 'security'
            elif re.search(r'lv\.?4|level\s*4', section):
                level = 'lv4'
            elif re.search(r'lv\.?3|level\s*3', section):
                level = 'lv3'
    except Exception:
        pass

# Lv.3+ 판정
lv3_keywords = ('critical', 'security', 'lv3', 'lv4', 'lv.3', 'lv.4')
is_lv3 = any(kw in level for kw in lv3_keywords)
if not is_lv3 and level:
    import re as _re
    is_lv3 = bool(_re.search(r'level\s*[34]', level))
print('lv3plus' if is_lv3 else 'below')
" 2>/dev/null || echo "below")

if [ "$TASK_LEVEL" = "lv3plus" ]; then
    echo "[G3-GATE] Lv.3+ 감지 — g3_independent_verifier 실행."
    set +e
    python3 "$WORKSPACE/scripts/g3_independent_verifier.py" --task-id "$TASK_ID" 2>&1
    G3_EXIT=$?
    set -e
    if [ "$G3_EXIT" -ne 0 ]; then
        echo "[G3-GATE] FAIL — .done 생성 차단. g3_verifier exit code=$G3_EXIT"
        # .g3-failed 이벤트 생성 (QC FAIL 패턴과 동일)
        echo '{"task_id":"'"$TASK_ID"'","team":"'"$TEAM_SHORT"'","fail_reason":"G3 FAIL","timestamp":"'"$(date -Iseconds)"'"}' > "$EVENTS_DIR/${TASK_ID}.g3-failed"
        exit 1
    fi
    echo "[G3-GATE] PASS — g3 검증 통과."
else
    echo "[G3-GATE] Lv.2 이하 — g3_verifier 스킵."
fi

# 2.9. Lv.4 보안 감사 검증 (WARNING only — 첫 단계)
if [ "$TASK_LEVEL" = "lv3plus" ]; then
    IS_LV4=$(python3 -c "
import re
task_file = '$WORKSPACE/memory/tasks/$TASK_ID.md'
try:
    with open(task_file) as f:
        content = f.read()
    m = re.search(r'## 레벨\s*\n(.*?)(?=\n## |\Z)', content, re.DOTALL)
    if m:
        section = m.group(1).strip().lower()
        if 'critical' in section or 'security' in section or re.search(r'lv\.?4|level\s*4', section):
            print('yes')
        else:
            print('no')
    else:
        print('no')
except Exception:
    print('no')
" 2>/dev/null || echo "no")

    if [ "$IS_LV4" = "yes" ]; then
        echo "[LV4-AUDIT] Lv.4 감지 — 보안 감사 검증 시작."

        # 2.9.1 security-audit 이벤트 파일 체크
        SECURITY_AUDIT_FILE="$EVENTS_DIR/${TASK_ID}.security-audit"
        if [ ! -f "$SECURITY_AUDIT_FILE" ]; then
            echo "[LV4-AUDIT] ⚠️ WARNING: security-audit 파일 없음 ($SECURITY_AUDIT_FILE)"
            echo "[LV4-AUDIT] Lv.4 작업은 보안 감사 결과 파일이 필수입니다. .done 차단."
            exit 1
        else
            echo "[LV4-AUDIT] ✅ security-audit 파일 존재 확인."
        fi

        # 2.9.2 로키 보안 감사 참여 기록 체크 (보고서에서)
        REPORT_FILE="$WORKSPACE/memory/reports/${TASK_ID}.md"
        if [ -f "$REPORT_FILE" ]; then
            LOKI_SECURITY=$(python3 -c "
import re
report_path = '$REPORT_FILE'
try:
    with open(report_path) as f:
        content = f.read()
    has_loki = bool(re.search(r'로키|Loki|loki', content))
    has_security = bool(re.search(r'보안 감사|security audit|레드팀|red.?team', content, re.IGNORECASE))
    if has_loki and has_security:
        print('PASS')
    elif has_loki:
        print('PARTIAL')
    else:
        print('MISSING')
except Exception:
    print('ERROR')
" 2>/dev/null || echo "ERROR")

            case "$LOKI_SECURITY" in
                PASS)
                    echo "[LV4-AUDIT] ✅ 로키 보안 감사 참여 기록 확인."
                    ;;
                PARTIAL)
                    echo "[LV4-AUDIT] ⚠️ WARNING: 로키 참여 기록은 있으나 보안 감사 명시 없음."
                    ;;
                MISSING)
                    echo "[LV4-AUDIT] ⚠️ WARNING: 로키 보안 감사 참여 기록 없음."
                    echo "[LV4-AUDIT] Lv.4 작업은 로키 레드팀 보안 감사가 필수입니다. .done 차단."
                    exit 1
                    ;;
                *)
                    echo "[LV4-AUDIT] ⚠️ WARNING: 보고서 파싱 실패."
                    ;;
            esac
        else
            echo "[LV4-AUDIT] ⚠️ WARNING: 보고서 파일 없음 — 로키 참여 확인 불가."
        fi

        echo "[LV4-AUDIT] Lv.4 보안 감사 검증 완료 (FAIL 게이트 적용)."
    fi
fi

# 2.10. Codex 사전검증 결과 파일 체크 (Lv.3+ 작업에만 적용)
if [ "$TASK_LEVEL" = "lv3plus" ]; then
    CODEX_GATE_FILE="$EVENTS_DIR/${TASK_ID}.codex-gate"
    if [ -f "$CODEX_GATE_FILE" ]; then
        CODEX_PASS=$(python3 -c "
import json
try:
    with open('$CODEX_GATE_FILE') as f:
        data = json.load(f)
    print('PASS' if data.get('pass', False) else 'FAIL')
except Exception:
    print('UNKNOWN')
" 2>/dev/null || echo "UNKNOWN")
        echo "[CODEX-GATE] Codex 사전검증 결과 파일 존재: $CODEX_PASS"
    else
        echo "[CODEX-GATE] WARNING: Codex 사전검증 결과 파일 없음 ($CODEX_GATE_FILE). Codex 게이트가 실행되지 않았습니다."
    fi
else
    echo "[CODEX-GATE] Lv.2 이하 — Codex 게이트 체크 스킵."
fi

# 2.11. Unresolved Issue Gate
UNRESOLVED_RESULT_VAL="PASS"
UNRESOLVED_ENABLED=$(python3 -c "from utils.gate_config_loader import is_gate_enabled; print(is_gate_enabled('unresolved_gate'))" 2>/dev/null || echo "false")
if [ "$UNRESOLVED_ENABLED" = "True" ]; then
    UNRESOLVED_MODE=$(python3 -c "from utils.gate_config_loader import get_gate_mode; print(get_gate_mode('unresolved_gate'))" 2>/dev/null || echo "warn")
    if [ -f "$REPORT_FILE" ]; then
        UNRESOLVED_COUNT=$(grep -ciE "범위 내 미해결|in.scope.*unresolved" "$REPORT_FILE" 2>/dev/null | tail -1 || echo "0")
        UNRESOLVED_COUNT="${UNRESOLVED_COUNT:-0}"
        MAX_UNRESOLVED=$(python3 -c "from utils.gate_config_loader import load_gate_config; print(load_gate_config('unresolved_gate').get('max_in_scope_unresolved', 3))" 2>/dev/null || echo "3")
        echo "[UNRESOLVED-GATE] count=$UNRESOLVED_COUNT max=$MAX_UNRESOLVED mode=$UNRESOLVED_MODE"
        if [ "$UNRESOLVED_COUNT" -gt "$MAX_UNRESOLVED" ]; then
            UNRESOLVED_RESULT_VAL="BLOCK"
            if [ "$UNRESOLVED_MODE" = "fail" ]; then
                echo "[UNRESOLVED-GATE] BLOCKED"
                exit 1
            fi
        elif [ "$UNRESOLVED_COUNT" -gt 0 ]; then
            UNRESOLVED_RESULT_VAL="WARN"
        fi
    fi
else
    echo "[UNRESOLVED-GATE] disabled — 스킵."
fi

# 2.12. Goal Assertions Gate
GOAL_RESULT_VAL="PASS"
GOAL_ENABLED=$(python3 -c "from utils.gate_config_loader import is_gate_enabled; print(is_gate_enabled('goal_assertions'))" 2>/dev/null || echo "false")
if [ "$GOAL_ENABLED" = "True" ]; then
    GOAL_MODE=$(python3 -c "from utils.gate_config_loader import get_gate_mode; print(get_gate_mode('goal_assertions'))" 2>/dev/null || echo "fail")
    if [ -f "$TASK_FILE" ]; then
        GOALS=$(python3 -c "
import re
with open('$TASK_FILE') as f:
    content = f.read()
m = re.search(r'## goal_assertions.*?\n(.*?)(?=\n##|\Z)', content, re.S)
if m:
    for line in m.group(1).strip().split('\n'):
        cmd = re.search(r'\x60([^\x60]+)\x60', line)
        if cmd:
            print(cmd.group(1))
" 2>/dev/null)
        # allowed_commands 화이트리스트 로드
        ALLOWED_CMDS=$(python3 -c "from utils.gate_config_loader import load_gate_config; print(' '.join(load_gate_config('goal_assertions').get('allowed_commands', [])))" 2>/dev/null || echo "grep curl pytest python3 tsc cat jq npx npm")
        GOAL_FAIL=0
        while IFS= read -r cmd; do
            [ -z "$cmd" ] && continue
            # 명령의 첫 단어 추출 및 화이트리스트 검증
            FIRST_WORD=$(echo "$cmd" | awk '{print $1}')
            ALLOWED=0
            for acmd in $ALLOWED_CMDS; do
                if [ "$FIRST_WORD" = "$acmd" ]; then
                    ALLOWED=1
                    break
                fi
            done
            if [ $ALLOWED -eq 0 ]; then
                echo "[GOAL-GATE] SKIP (not in allowed_commands): $cmd"
                continue
            fi
            set +e
            eval "$cmd" > /dev/null 2>&1
            CMD_EXIT=$?
            set -e
            if [ $CMD_EXIT -ne 0 ]; then
                echo "[GOAL-GATE] FAIL: $cmd"
                GOAL_FAIL=1
            fi
        done <<< "$GOALS"
        if [ $GOAL_FAIL -eq 1 ]; then
            GOAL_RESULT_VAL="FAIL"
            if [ "$GOAL_MODE" = "fail" ]; then
                echo "[GOAL-GATE] BLOCKED: goal_assertions 미충족"
                exit 1
            fi
        fi
    fi
else
    echo "[GOAL-GATE] disabled — 스킵."
fi

# l1_smoketest 결과 수집 (.qc-result에서)
L1_RESULT_VAL="PASS"
if [ -f "$QC_RESULT_FILE" ]; then
    L1_FROM_QC=$(python3 -c "
import json
try:
    with open('$QC_RESULT_FILE') as f:
        data = json.load(f)
    checks = data.get('checks_summary', {})
    l1 = checks.get('l1_smoketest_check', checks.get('l1_smoketest', 'PASS'))
    print(l1)
except Exception:
    print('PASS')
" 2>/dev/null || echo "PASS")
    if [ "$L1_FROM_QC" = "FAIL" ]; then
        L1_RESULT_VAL="FAIL"
    fi
fi

# 3. .done 원자적 생성 (qc_result 포함)
if ! (set -C; python3 -c "
import json, sys
data = {
    'task_id': '$TASK_ID',
    'team': '$TEAM_SHORT',
    'qc_result': '$QC_STATUS',
    'completed_at': '$(date -Iseconds)',
    'status': 'done',
    'gate_results': {
        'impact_scanner': '$IMPACT_RESULT_VAL',
        'ci_preflight': '$CI_RESULT_VAL',
        'l1_smoketest': '$L1_RESULT_VAL',
        'goal_assertions': '$GOAL_RESULT_VAL',
        'unresolved_gate': '$UNRESOLVED_RESULT_VAL',
    },
}
with open('$DONE_FILE', 'x') as f:
    json.dump(data, f, ensure_ascii=False, indent=2)
") 2>/dev/null; then
    echo "[WARN] .done already exists: $DONE_FILE"
fi

# 4. task-timer end에 qc_result 전달
if [ -n "$QC_STATUS" ]; then
    python3 "$WORKSPACE/memory/task-timer.py" end "$TASK_ID" --qc-result "$QC_STATUS" 2>&1 || echo "[WARN] task-timer end failed"
else
    python3 "$WORKSPACE/memory/task-timer.py" end "$TASK_ID" 2>&1 || echo "[WARN] task-timer end failed"
fi

# 5. notify-completion.py
source "$WORKSPACE/.env.keys" 2>/dev/null || true
python3 "$WORKSPACE/scripts/notify-completion.py" "$TASK_ID" 2>&1 || echo "[WARN] notify-completion failed"

echo "[OK] finish-task.sh completed for $TASK_ID"
