# QC 런타임 검증 가이드

> **작성자**: 아테나 (개발1팀 UX/UI 설계자)
> **지시자**: 헤르메스 팀장
> **대상 독자**: 마아트 (QC 매니저)
> **최종 수정**: 2026-03-02

---

## 검증 원칙

> "개발자 보고를 절대 신뢰하지 않는다. 모든 것을 직접 실행하여 검증한다."
> — 마아트의 QC 원칙

개발팀이 "완료"를 선언하더라도, QC는 반드시 아래 4가지 항목을 직접 실행하여 독립적으로 확인한다. 보고서와 실제 상태가 불일치할 경우 즉시 FAIL 처리하고 재작업을 요청한다.

---

## 체크리스트 요약

| # | 항목 | 검증 방법 | 상태 |
|---|------|-----------|------|
| 1 | 서버 검증 | curl API 응답 확인 | [ ] |
| 2 | 프로세스 검증 | 실행 디렉토리 및 포트 바인딩 확인 | [ ] |
| 3 | 파일 검증 | 생성 위치 및 권한 확인 | [ ] |
| 4 | 데이터 정합성 | 원본 데이터와 결과물 일치 확인 | [ ] |

---

## 1. 서버 검증

### 목적
서버가 올바른 포트에서 정상적으로 응답하는지, API가 기대하는 형식의 데이터를 반환하는지 직접 확인한다.

### 명령어

**기본 API 응답 확인**
```bash
curl -s http://localhost:<PORT>/api/<endpoint> | python3 -m json.tool
```

**HTTP 상태 코드 포함 확인**
```bash
curl -s -o /dev/null -w "%{http_code}" http://localhost:<PORT>/api/<endpoint>
```

**헤더 포함 전체 응답 확인**
```bash
curl -sv http://localhost:<PORT>/api/<endpoint> 2>&1 | head -50
```

**Content-Type 확인**
```bash
curl -sI http://localhost:<PORT>/api/<endpoint> | grep -i content-type
```

### 예시

```bash
# 포트 8080에서 실행 중인 서버의 /api/status 엔드포인트 확인
curl -s http://localhost:8080/api/status | python3 -m json.tool

# 기대 출력 예시
{
    "status": "ok",
    "version": "1.0.0",
    "timestamp": "2026-03-02T10:00:00Z"
}

# HTTP 상태 코드 확인
curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/api/status
# 기대 출력: 200
```

### 기대 결과

| 항목 | 정상 값 | 비정상 값 |
|------|---------|-----------|
| HTTP 상태 코드 | `200` (인증 필요 시 `401`) | `404`, `500`, `connection refused` |
| Content-Type | `application/json` | `text/html`, 빈 응답 |
| 응답 구조 | 필수 필드 모두 존재 | 필드 누락, 빈 객체 `{}` |
| 응답 파싱 | `python3 -m json.tool` 오류 없음 | JSON 파싱 오류 |

### 판정 기준

- **PASS**: HTTP 200 응답, `application/json` Content-Type, 필수 필드 모두 존재, JSON 파싱 성공
- **FAIL**: 응답 없음(`connection refused`), HTTP 500 이상 오류, JSON 파싱 실패, 필수 필드 누락

---

## 2. 프로세스 검증

### 목적
서버 프로세스가 실제로 실행 중인지, 올바른 디렉토리에서 기동되었는지, 지정된 포트에 바인딩되어 있는지 확인한다.

### 명령어

**프로세스 실행 여부 및 PID 확인**
```bash
ps aux | grep <process_name> | grep -v grep
```

**실행 디렉토리 확인 (PID 필요)**
```bash
ls -la /proc/<PID>/cwd
```

**포트 바인딩 확인**
```bash
ss -tlnp | grep <PORT>
```

**프로세스 상세 정보 확인**
```bash
cat /proc/<PID>/cmdline | tr '\0' ' '
```

**환경변수 확인**
```bash
cat /proc/<PID>/environ | tr '\0' '\n' | grep -E "PORT|ENV|NODE_ENV"
```

### 예시

```bash
# 1. 프로세스 확인 (예: node 프로세스)
ps aux | grep node | grep -v grep
# 기대 출력 예시:
# jay  12345  0.5  1.2  /usr/bin/node server.js

# 2. 실행 디렉토리 확인
ls -la /proc/12345/cwd
# 기대 출력 예시:
# lrwxrwxrwx 1 jay jay 0 Mar  2 10:00 /proc/12345/cwd -> /home/jay/workspace/projects/proj-001

# 3. 포트 바인딩 확인
ss -tlnp | grep 8080
# 기대 출력 예시:
# LISTEN  0  511  0.0.0.0:8080  0.0.0.0:*  users:(("node",pid=12345,fd=18))
```

### 기대 결과

| 항목 | 정상 상태 | 비정상 상태 |
|------|-----------|-------------|
| 프로세스 존재 | PID가 출력됨 | 출력 없음 (프로세스 미실행) |
| 실행 디렉토리 | 지정된 프로젝트 경로 | 예상치 못한 경로 또는 `/tmp` |
| 포트 바인딩 | 지정 PORT에 LISTEN | 포트 없음 또는 다른 포트 |

### 판정 기준

- **PASS**: 프로세스 실행 중, 올바른 디렉토리에서 기동, 지정 포트 LISTEN 상태
- **FAIL**: 프로세스 없음, 잘못된 디렉토리(예: `/tmp`, 다른 팀 디렉토리), 포트 바인딩 없음

---

## 3. 파일 검증

### 목적
작업 결과물이 팀별 규칙에 따른 올바른 디렉토리에 생성되었는지, 다른 팀의 디렉토리를 침범하지 않았는지 확인한다.

### 팀별 작업 디렉토리 규칙

| 팀 | 기본 디렉토리 | 프로젝트 격리 경로 |
|----|--------------|-------------------|
| dev1-team | `/home/jay/workspace/teams/dev1/` | `/home/jay/workspace/projects/<project_id>/` |
| dev2-team | `/home/jay/workspace/teams/dev2/` | `/home/jay/workspace/projects/<project_id>/` |
| dev3-team | `/home/jay/workspace/teams/dev3/` | `/home/jay/workspace/projects/<project_id>/` |

### 명령어

**파일 존재 여부 확인**
```bash
ls -la /home/jay/workspace/teams/<team>/<expected_file>
```

**파일 크기 및 권한 확인**
```bash
stat /home/jay/workspace/teams/<team>/<expected_file>
```

**디렉토리 내 전체 파일 목록**
```bash
find /home/jay/workspace/teams/<team>/ -type f -ls
```

**다른 팀 디렉토리 침범 여부 확인**
```bash
# dev1-team 작업 후 다른 팀 디렉토리에 예상치 못한 파일이 생겼는지 확인
find /home/jay/workspace/teams/dev2/ -newer /home/jay/workspace/teams/dev2/.baseline -type f 2>/dev/null
find /home/jay/workspace/teams/dev3/ -newer /home/jay/workspace/teams/dev3/.baseline -type f 2>/dev/null
```

**파일 내용 빠른 검증**
```bash
# JSON 파일 유효성 확인
python3 -m json.tool < /home/jay/workspace/teams/<team>/<file>.json

# 파일 행 수 및 크기 확인
wc -l /home/jay/workspace/teams/<team>/<file>
```

### 예시

```bash
# dev1-team 산출물 확인
ls -la /home/jay/workspace/teams/dev1/
# 기대 출력:
# -rw-r--r-- 1 jay jay 2048 Mar  2 10:00 report.json
# -rw-r--r-- 1 jay jay  512 Mar  2 10:00 output.done

# 파일 크기가 0이 아닌지 확인
stat /home/jay/workspace/teams/dev1/report.json | grep Size
# 기대 출력: Size: 2048  (0이면 FAIL)

# 다른 팀 디렉토리에 불필요한 파일이 없는지 확인
ls /home/jay/workspace/teams/dev2/
ls /home/jay/workspace/teams/dev3/
# 기대: dev1 작업 관련 파일 없음
```

### 기대 결과

| 항목 | 정상 상태 | 비정상 상태 |
|------|-----------|-------------|
| 파일 위치 | 팀 지정 디렉토리 내 | 다른 팀 디렉토리, `/tmp`, 홈 루트 |
| 파일 크기 | > 0 bytes | 0 bytes (빈 파일) |
| 파일 권한 | `rw-r--r--` (644) 또는 명세 기준 | 실행 불필요한 파일에 실행 권한 |
| 타 팀 침범 | 없음 | 다른 팀 디렉토리에 새 파일 생성됨 |

### 판정 기준

- **PASS**: 파일이 지정 경로에 존재, 크기 > 0, 올바른 권한, 타 팀 디렉토리 변경 없음
- **FAIL**: 파일 없음, 빈 파일(0 bytes), 잘못된 위치, 타 팀 디렉토리 침범

---

## 4. 데이터 정합성

### 목적
대시보드 또는 보고서에 표시된 데이터가 실제 원본 데이터와 일치하는지 확인한다. 개발자가 보고한 상태와 실제 파일 상태가 동기화되어 있는지 직접 대조한다.

### 주요 검증 파일

| 파일 | 경로 | 용도 |
|------|------|------|
| task-timers | `/home/jay/workspace/memory/task-timers.json` | 작업 상태 및 타이머 추적 |
| 이벤트 파일 | `<작업경로>/<task_id>.done` | 작업 완료 이벤트 마커 |
| 보고서 파일 | 팀별 작업 디렉토리 내 `report.json` | 작업 결과 요약 |

### 명령어

**task-timers.json 상태 확인**
```bash
python3 -m json.tool /home/jay/workspace/memory/task-timers.json
```

**특정 태스크 상태 추출**
```bash
python3 -c "
import json
with open('/home/jay/workspace/memory/task-timers.json') as f:
    data = json.load(f)
# 태스크 상태 출력
for task_id, info in data.items():
    print(f'{task_id}: {info.get(\"status\", \"unknown\")}')
"
```

**완료 이벤트 파일(.done) 존재 확인**
```bash
find /home/jay/workspace/ -name "*.done" -type f -ls
```

**보고서와 실제 결과물 비교**
```bash
# 보고서에 명시된 파일 목록과 실제 존재 파일 대조
python3 -c "
import json, os
with open('/home/jay/workspace/teams/<team>/report.json') as f:
    report = json.load(f)
for filepath in report.get('output_files', []):
    exists = os.path.exists(filepath)
    size = os.path.getsize(filepath) if exists else 0
    print(f'[{\"OK\" if exists and size > 0 else \"FAIL\"}] {filepath} ({size} bytes)')
"
```

**task-timers.json과 .done 파일 정합성 교차 확인**
```bash
# task-timers에서 completed 상태인 태스크에 .done 파일이 실제로 있는지 확인
python3 -c "
import json, os
with open('/home/jay/workspace/memory/task-timers.json') as f:
    data = json.load(f)
for task_id, info in data.items():
    if info.get('status') == 'completed':
        done_path = info.get('done_file', '')
        if done_path:
            exists = os.path.exists(done_path)
            print(f'[{\"OK\" if exists else \"MISSING .done\"}] {task_id}: {done_path}')
"
```

### 예시

```bash
# 1. task-timers.json 상태 확인
python3 -m json.tool /home/jay/workspace/memory/task-timers.json
# 기대 출력 예시:
# {
#     "task-001": {
#         "status": "completed",
#         "team": "dev1-team",
#         "done_file": "/home/jay/workspace/teams/dev1/task-001.done"
#     }
# }

# 2. .done 파일 실제 존재 확인
ls -la /home/jay/workspace/teams/dev1/task-001.done
# 기대 출력:
# -rw-r--r-- 1 jay jay 64 Mar  2 10:00 task-001.done

# 3. .done 파일이 없는데 completed 상태면 FAIL
```

### 기대 결과

| 항목 | 정상 상태 | 비정상 상태 |
|------|-----------|-------------|
| task-timers.json 파싱 | JSON 파싱 성공 | 파싱 오류 (파일 손상) |
| completed 태스크의 .done 파일 | 파일 존재 | .done 파일 없음 |
| 보고서 명시 파일 | 실제로 존재하고 크기 > 0 | 파일 없음 또는 빈 파일 |
| 타이머 상태와 실제 결과 | 일치 | 불일치 (상태는 completed, 결과물 없음) |

### 판정 기준

- **PASS**: task-timers.json 정상 파싱, 모든 completed 태스크에 .done 파일 존재, 보고서 파일과 실제 결과물 일치
- **FAIL**: JSON 파싱 오류, .done 파일 누락, 보고서와 실제 결과물 불일치, 상태-결과물 간 불일치

---

## 최종 판정

### 전체 PASS 조건
4가지 항목 **모두** PASS여야 최종 PASS 판정.

### FAIL 처리 절차
1. FAIL 항목과 구체적인 불일치 내용을 기록한다.
2. 해당 팀장(헤르메스)에게 즉시 보고한다.
3. 담당 팀에 재작업을 요청한다.
4. 재작업 완료 후 해당 항목만 재검증한다.

### 검증 결과 기록 양식

```
## QC 검증 결과
- 검증 일시: YYYY-MM-DD HH:MM
- 검증자: 마아트
- 대상 태스크: <task_id>
- 담당 팀: <team>

| 항목 | 결과 | 비고 |
|------|------|------|
| 서버 검증 | PASS / FAIL | |
| 프로세스 검증 | PASS / FAIL | |
| 파일 검증 | PASS / FAIL | |
| 데이터 정합성 | PASS / FAIL | |

최종 판정: PASS / FAIL
```

---

*이 문서는 헤르메스 팀장의 지시로 아테나(개발1팀 UX/UI 설계자)가 작성하였습니다.*
