제 2 장

요구사항 분석

1) 문제 정의

제 1 장의 배경을 시스템이 풀어야 할 문제로 좁히면 넷이다.

P1. 예측의 근거가 남지 않는다. 승자만 저장하면 그 예측이 무엇을 보고 나온 것인지 사후에 알 수 없다. 모델을 다시 불러 같은 답이 나오는지 확인하는 것은 근거의 재구성이 아니다 — 그 사이 코퍼스도 모델도 바뀐다.

P2. 결과를 읽고 낸 예측이 성능으로 집계된다. 대회 문서에는 경기 결과가 적혀 있다. 그것을 근거로 검색해 온 예측은 겉보기에 정확하고, 적중률만 세면 구별되지 않는다.

P3. 시간을 확인할 수 없는 자료가 섞인다. 글이 언제 쓰였는지 모르면 “그때 있던 정보”인지 판정할 수 없다. 모른다는 사실 자체가 기록돼야 하며, 모름을 통과로도 실격으로도 처리해서는 안 된다.

P4. 표본이 작은데 숫자가 커 보인다. 12건 중 12건을 맞히면 적중률 100%다. 분모 없이 그 백분율만 세우면 과장이 된다.

2) 사용자 요구사항

# 요구 근거
U1 다가오는 PLE의 대진을 보고 경기별로 픽을 고를 수 있어야 한다 제품의 기본 동작
U2 경기 형식에 따라 난이도가 다르므로 배점도 달라야 한다 6인 래더와 싱글을 같은 점수로 치면 순위가 운을 따른다
U3 제출한 픽은 잠기고, 결과가 나오면 자동으로 채점돼야 한다 사후 수정이 가능하면 순위가 의미를 잃는다
U4 AI가 왜 그 선수를 골랐는지 근거 문장을 볼 수 있어야 한다 승자만 보여 주면 신뢰할 근거가 없다
U5 AI의 적중률을 믿어도 되는지를 함께 알 수 있어야 한다 P2 · P4
U6 선수·경기·챔피언십 기록을 찾아볼 수 있어야 한다 예측의 재료

U5가 이 프로젝트를 정의하는 요구다. 나머지 다섯은 예측 서비스라면 대체로 갖는 것이고, U5가 있어서 AI LAB이라는 화면 묶음이 따로 선다.

3) 기능 요구사항

예측·랭킹

  • F1 대진표 관리 — 대진의 원본은 프론트 픽스처이고, 방문자가 페이지를 열 때 동기화 API로 DB에 반영된다. 위키에서 대진을 읽어 픽스처를 갱신하는 도구가 그 앞단에 있다.
  • F2 픽 제출 — 경기 단위로 제출하며 제출 즉시 잠긴다.
  • F3 채점·배점 — 경기 형식과 타이틀 여부로 점수가 결정된다(제 5 장 3절).
  • F4 라이브 갱신 — 진행 중인 대회의 투표 현황을 서버가 밀어 준다.

데이터 센터

  • F5 선수·경기·챔피언십 집계 — 같은 선수의 전적이 화면마다 달라지지 않도록 집계 규칙을 한 모듈에 둔다.
  • F6 표본이 모자라면 숫자를 내지 않는다 — 0%로 채우지 않고 칸을 비운다.

AI LAB

  • F7 예측 생성 — 세 에이전트가 각자 리포트를 내고 합성한다.
  • F8 계보 기록 — 검색 질의 · 읽은 청크의 본문과 개정본 시각을 예측과 함께 저장한다.
  • F9 자격 판정 — 여덟 규칙으로 제외·실격·보류를 가른다.
  • F10 재현 — 저장된 값으로 질의 조립과 리포트 합성을 다시 돌려 대조한다.
  • F11 누수 귀속 — 어느 문서가 어느 예측을 막았는지 보여 준다.
  • F12 준비도 — 예측을 만들기 전에 그 대회의 코퍼스가 깨끗한지 본다.

4) 비기능 요구사항

# 요구 어떻게 강제하는가
N1 도메인 로직이 프레임워크·DB를 모른다 헥사고날 레이어 + import-linter 계약
N2 앱 사이의 의존은 허브를 통해서만 스타 토폴로지 계약 (스포크 ↔ 스포크 금지)
N3 없는 값을 지어내지 않는다 표본 부족 시 None 반환 · 화면이 사유를 적는다
N4 판정 규칙은 한 곳에서만 정의된다 화면과 배치 스크립트가 같은 유스케이스를 부른다
N5 쓰기 스크립트는 기본이 드라이런 --apply 없이는 출력만
N6 무료 LLM 등급의 하루 한도 안에서 돈다 모델별 분산 + 하루 경기 수 상한
N7 회귀는 커밋 전에 막는다 pre-commit 훅 10종 + GitHub Actions

N3과 N4가 가장 자주 부딪히는 요구다. 화면이 “이 대회는 깨끗하다”고 말하는데 배치 스크립트가 따로 세어 건너뛰면, 둘 중 어느 쪽이 맞는지 아무도 모르는 상태가 된다. 그래서 자동 생성 스크립트는 준비도를 자기가 계산하지 않고 /ai-lab/readiness가 부르는 유스케이스를 그대로 부른다.