UI 렌더링 없이 게임 로직 계층을 배치모드에서 실제 구동해 주인공 마테오의 단일 연속 스토리를 대단원까지 완주시키고, 경제 시세 모델·바람장 항해·측량·세이브 왕복을 불변식으로 검증했습니다. 이어 실제 macOS 스탠드얼론 앱을 빌드해 패키징 가능성까지 확인했습니다.
| 플레이 흐름 | 상태 |
|---|---|
| 타이틀 → 새 항해 / 이어하기 (1530) | 구현 |
| 주인공 마테오 카브레라 (단일 · 스탯·시작조건) | 구현 |
| 오프닝 크롤 + 귀환 프롤로그 | 구현 |
| 항구 허브 6시설 (교역/조선/주점/은행/함대/저장) | 구현 |
| 나소 밀무역 시장 · 현상금 게시판 | 구현 |
| 세계지도 실시간 항해 (바람·보급·수급경제) | 구현 |
| 전투 (라운드제 + 진형 3종) | 구현 |
| 스토리 18이벤트 (귀환~배신 반전~엔딩~대단원, 단일 연속 서사) | 구현 |
| 측량 시스템 · 은퇴 회고(1555) · 세이브 | 구현 |
=== 검은 수평선 · 헤드리스 플레이스루 QA === 실행: batchmode · Unity 6000.3.11f1 · 2026-07-12 04:49 ── 콘텐츠 데이터 무결성 [PASS] 항구 로드 — 32개 [PASS] 교역품 로드 [PASS] 함선 로드 [PASS] 주인공 1인(마테오) [PASS] 주인공 시작 항구 유효 [PASS] 이벤트 항구 참조 유효 [PASS] 대사 포트레이트 참조 유효 · 총 스토리 이벤트 37개 ── 경제 시세 모델 [PASS] 모든 가격 양수 · 최저가 17 (곡물@나폴리) / 최고가 686 (금@라스팔마스) [PASS] 특산지 저가·원거리 고가 — 설탕 마데이라 64 → 런던 106 (+42) [PASS] 수급 연동(매수→상승) — 64 → 76 [PASS] 은행 이자 9,999닢 = 299(3%) — 299 [PASS] 은행 이자 10,000닢 = 300(경계 3% 포함) — 300 [PASS] 은행 이자 10,001닢 = 300(초과 1닢×1%=0, 캡 발동) — 300 [PASS] 은행 이자 0/음수 방어 = 0 [PASS] 은행 이자 구간 단조 증가 [PASS] 은행 복리 캡 효과(100만닢 캡 < 무상한 3%) — 캡 10200 vs 무상한 30000 ── 항해 시뮬레이션 (30일) [PASS] 바람장·속도 계산 — 풍력 1.1, 속도 14.1노트 [PASS] 출항 후 외해 이탈(시작 항구에서 항해 가능) — 376스텝 · 18.8° 이동 · 종착 바다 [PASS] 보급 소모 진행 — 물 30→0, 식량 30→0 · 30일간 폭풍 2회 · 해적 조우 1회 (시드 1717) ── 사기·배급 (Slice 3) [PASS] 신규 게임 기본값 사기 70 · 배급 정상(1) — morale=70, rationLevel=1 [PASS] 구세이브 로드 → 사기 70 · 배급 1 (가산 필드 기본값) — morale=70, ration=1 [PASS] 손상 세이브 방어 클램프(0..100 / 0..2) [PASS] 정상 배급 소모 = 기존 공식(라운딩 동일) — 물 -1 · 식량 -1 (기대 1) [PASS] 절약·포식 배급 배수(ceil×0.7 · ×2) — 절약 -1 · 포식 -2 (기준 1) ── 사기 실효 (탈주 · 전투 재장전) [PASS] 탈주 경계: 사기 20 → 0 · 사기 19 → >0 — 20→0 · 19→9 [PASS] 탈주 해시 결정론(동일 입력 → 동일 인원) — 7=7 [PASS] 탈주 비율 밴드 5~10% + 최소 1 — 전 표본 [0.05,0.10] · ≥1 [PASS] 탈주 가드(잔류 ≥ keepFloor · 바닥에선 0) — cap2→1 · floor→0 · below→0 [PASS] 사기 20~100 전 구간 탈주 0(순항 방어선) [PASS] 재장전 계수 경계(39=1.05 · 40=1.00 · 89=1.00 · 90=0.95 · 70=1.00) — 39=1.05 40=1 89=1 90=0.95 70=1 [PASS] 사기 40~89 재장전 비트 동일(FireCD×1.0f == FireCD) [PASS] 재장전 계수 단조(저사기 느림 ≥ 순항 ≥ 고사기 빠름) — 1.05 ≥ 1 ≥ 0.95 ── 질병·지리 발견 (Slice 4) [PASS] 랜드마크 id 유일 [PASS] 랜드마크 좌표 전부 바다 셀 [PASS] 랜드마크 항구와 0.5° 이상 이격 · 명명 지형 24곳 [PASS] 발견 추가 + 모험 명성 +40 — 명성 +40 [PASS] 재접근 중복 방지(명성 불변) [PASS] 사거리 밖 미발견 [PASS] 질병 결정론(동일 상태·동일 day → 동일 결과) — sickDays 0=0 [PASS] 정상 상태 30일 무발병 — 사기 70 [PASS] 구세이브 로드 → 질병 0 · 발견 빈 리스트 — sickDays=0, 발견=0 ── 측량 시스템 [PASS] 미답 격자 기록 — 24개 신규 구역 [PASS] 중복 미기록 [PASS] 판매 대기 집계 — 24건 ── 발견 보고 경제 (학회 정보 판매) [PASS] 보고 포상 하한 = base(거리 0·곶 → 가중 0) — 150 == 150 [PASS] 보고 포상 종류 단조(곶<섬<암초<해협) — 248<298<348<398 [PASS] 보고 포상 원거리 단조(원양 > 근해) — 근해 270 < 원양 565 [PASS] 보고 포상 전 랜드마크 밴드[150,900] — min 187 · max 663 · 24곳 총 10,606닢 [PASS] 미보고 집계 = 발견−보고 — 2 [PASS] 모두 보고: 골드·교역 명성 가산 · 모험 명성 불변 — +441닢(기대 441) · 교역명성 0→6 · 모험명성 0→0 [PASS] 보고 후 미보고 0 — 0 [PASS] 재보고 차단(건수·골드·명성 불변) — 재보고 count=0 gold=0 [PASS] 미발견 → 보고 불가(상태 불변) [PASS] 발견 ≠ 자동 보고(발견 직후 미보고 1) — 발견 1 · 미보고 1 [PASS] 구세이브 소급(reported 부재 → 발견분 전부 미보고) — 발견 3 · 미보고 3 · reported 0 ── 사관(항해사) 영입 (Slice 5) [PASS] 사관 데이터: id 유일 [PASS] 사관 데이터: 비용 > 0 · 티어 1~3 [PASS] 사관 데이터: 5역할 전부 존재 — 5역할 · 16명 [PASS] 고용 성공(골드 차감 · 명단 추가 · power 조회) — 골드 -2400 · power 2 [PASS] 역할 중복 거부(골드·명단 불변) [PASS] 자금 부족 거부(상태 불변) [PASS] 미고용 SpeedKnots 현행 동일(결정론) — 14.081 == 14.081 [PASS] 항해장 고용 → 속도 증가(+6%) — 14.08 → 14.93노트 [PASS] 세이브→로드 officers 보존 — 2명 [PASS] 구세이브 로드 → officers 빈 리스트(비-null) — officers=0 ── 나포(적선 포획) 시스템 [PASS] PrizeValue 가격 비례(2배 선가 → 2배 매각가) — 320/640 [PASS] PrizeValue 손상 비례(잔여 50% → 절반) — 160 [PASS] PrizeValue durFrac 클램프[0,1] — over=320 neg=0 [PASS] defId 매핑: 대표 스탯 3개 → 기대 선종 — bergantin/nao/galeon [PASS] defId 매핑 결정론 · 유효 선종 반환 — nao [PASS] 편입: 선원 차출 = minCrew · TotalCrew 보존 · 각 배 최소 1 — 차출 12 · TotalCrew 25→25 · 함대 2→3 [PASS] 이중 보상 방지: 나포선 내구는 loot 기준서 제외 · 대신 매각가/편입으로 지급 — loot기준 300→180 · 매각가 1040 ── 조선소 매각·개조 (DKW2 패리티) [PASS] 매각가 만내구(선가×0.45) — 1260 [PASS] 매각가 내구 절반 → 절반 — 630 [PASS] 매각가 내구 0 → 0 — 0 [PASS] 매각가 < 구매가(즉시 재매각 손해 · 스프레드 0.55) — 1260 < 2800 [PASS] 보강+만수리 매각가 = 미개조 만내구 매각가(보강 투자 미반영) — 보강 1260 == 미개조 1260 [PASS] 선창 확장 상한 = Def.cargo/8 — carabela 11 · galeon 32 [PASS] 늑재 보강 상한 = Def.durability/5 — carabela 22 · galeon 68 [PASS] 상한 도달 시 스텝0·비용0(선창) [PASS] 상한 도달 시 스텝0·비용0(늑재) [PASS] 선창 스텝이 상한 초과 안 함 — 4 [PASS] 개조 비용 체감 상승(늑재 후반 스텝 > 초반 스텝) — 초반 42 < 후반 82 [PASS] 개조 회계: 상한 도달·골드 차감·용량 반영 — cargoMod 11/11 · 총비용 403 · 용량 90→101 [PASS] 개조 저장 왕복 영속 · 구세이브 하위호환(0) — 왕복 cargo6/dur14 · 구세이브 cargo0/dur0 [PASS] 개조 0 비트 동일: MaxCargo/MaxDurability = Def · CargoCapacity = Σ Def.cargo — CargoCapacity 590 == Σ 590 [PASS] 매각 재배치: 정원 여유 → TotalCrew 보존·해산 0·함선 제거 — 해산 0 · TotalCrew 25→25 · 함대 2→1 [PASS] 매각 해산: 정원 부족 → 초과 선원 로스트(미리보기와 일치) — 미리보기 18 · 실제해산 18 [PASS] 매각 화물초과 가드: 만재 시 매각 차단(화물 증발 방지) — 적재 130 > 매각후용량 90 ── 함대전 결정론 난수 (전역 Random 치환 · 태스크 #49) [PASS] 배틀 시드 재현성(동일 입력 → 동일 시드) — 1369400278==1369400278 [PASS] 배틀 시드 분산(날·경도·위도·자산·적 포문·적 내구 각각 반영) — day=True lon=True lat=True gold=True guns=True dur=True [PASS] 배틀 시드 스윕 무충돌(12×12 day×gold 전부 유일) — 144/144 유일 [PASS] xorshift 범위 준수(NextFloat[0,1) 엄격 · Range fireCd/speed/loot · NextIndex[0,5) · 20k 표본) — u∈[0.000,1.000] [PASS] xorshift 스트림 전진(연속 드로우가 상수 아님) — first=0.6756 [PASS] xorshift 시퀀스 결정론(동일 시드 → 동일 수열) [PASS] 손상 단계 경계 정확(r<0.6 경상·r<0.3 중상 · 0/만내구 포함) — 100→0 · 60→0 · 59→1 · 30→1 · 29→2 · 0→2 [PASS] 손상 단계 방어·스케일 불변(max≤0·음수·개조 DurMax 배수 경계) — 50/0→0 · -5/100→2 · 120/200→0 · 119/200→1 · 59/200→2 [PASS] 손상 단계 단조 비감소(내구 감소 → 단계 비역행) [PASS] BattleMath 전역 Random 무소비(5개 수식 함수 2500회 호출 후 전역 난수열 불변 · 태스크 #59) — 전역 스트림 무오염 [PASS] FleeRoll 스트림 분포(1만 회 성공률 ≈ chance ±0.02 · 3개 chance) — 0.25→0.249 0.45→0.448 0.70→0.701 [PASS] 전리품 계수 분포(NextRange[3,6) 평균≈4.5±0.05 · 1만 표본) — 평균 4.490 · [3.00,6.00) ── 궁정·작위 (Slice 6) [PASS] TitleTier 경계 정합(249/250/700/1500/3000) [PASS] TitleTier ↔ TitleKo ↔ TitleForTier 명칭 일치 [PASS] 서임: 티어2 하사금 +800 · courtRank=2 · 모험 명성 +30 — got=2 · 골드 +800 · courtRank=2 · 명성 +30 [PASS] 재서임 불가(반환 0 · 골드·티어·명성 불변) [PASS] 건너뛰기 서임: 최고 티어(3) 하사금 2000만 1회 · 중간 소급 없음 — got=3 · 골드 +2000 (기대 2000, 소급합 3100) [PASS] 건너뛴 뒤 재서임 불가 [PASS] 경계 서임: 순수 명성 2970 → 명예 기사(3) 하사금 2000만 1회 — got=3 · 골드 +2000(기대 2000) · courtRank=3 · bonus=30 [PASS] 경계 재서임 차단: 하사 +30 자기충당 불가 → 제독 무서임(반환 0 · 골드·티어 불변) — again=0 · 골드 +0 · courtRank=3 [PASS] 경계 도달: 자격 명성 3000에서만 제독(4) 서임 성사(하사금 5000) — got=4 · 골드 +5000(기대 5000) · courtRank=4 [PASS] 명성 미달(tier 0) → 무서임(상태 불변) — got=0 courtRank=0 [PASS] 구세이브 로드 → courtRank·courtFameBonus 0(가산 필드 기본값) — courtRank=0 bonus=0 [PASS] 손상 세이브 방어 클램프(courtRank 0..4 · bonus 0..courtRank×보상) ── 칙명(궁정 의뢰) (Slice 7) [PASS] 생성 결정론(동일 week·port·rank → 동일 칙명) [PASS] 생성 kind 1..3 [PASS] 운송 파라미터 유효(비사치품·수량·목적항 궁정도시·손익 ≥1.3배) [PASS] 운송 수임(필드 세팅 · 기한 +60) — data='grain:20:venice' deadline=60 [PASS] 운송 달성 판정(목적항 밖 미달 → 목적항+화물 달성) [PASS] 운송 완수(화물 −20 · 골드 +1600 · 명성 +20 · 리셋) — 곡물=0 골드 +1600 명성 +20 kind=0 [PASS] 토벌 base 델타(base 스냅샷 · 2척 소탕서 달성 · 완수 +1000/+20 · 리셋) — base=0 골드 +1000 [PASS] 탐사 base 델타(base 스냅샷 · 신규 1곳 달성 · 완수 +2200 · 리셋) — base=0 골드 +2200 [PASS] 만료 리셋(기한 내 유지 → 초과 시 리셋 · 골드 불변 · 무패널티) — kind=0 골드 1200 [PASS] 구세이브 로드 → 칙명 필드 기본값(kind 0 · data "" · base 0 · deadline 0) — kind=0 data='' base=0 dl=0 [PASS] 손상 세이브 방어 클램프(kind 0..3 · data null→"") ── 통행선 상호작용 (해상 거래·요격) [PASS] 오퍼 결정론(같은 lane·week·상태 → 동일 오퍼) — 판매 linen×7@136 · 매입 wine×9@58 [PASS] 오퍼 착취 밴드(수량 6~14 · 가격 ±10% · 매입≠판매 품목) — 판매단가 136/시세 130 [PASS] 다른 week도 결정론 재현 [PASS] 접촉 기록1(빈 키 → 신형식 day|lane) — 100|lisbon~madeira [PASS] 접촉 기록2(같은 날 → 집합 확장) — 100|lisbon~madeira;sevilla~london [PASS] 같은 날 두 항로 모두 억제 · 미처리 항로는 자유 [PASS] 다음 날 리셋(어제 lane 억제 해제 · 새 날짜만 기록) — reset=True k2=101|venice~genoa [PASS] 같은 날·같은 항로 재기록 → 중복 무시 — 100|lisbon~madeira;sevilla~london [PASS] 구형식 키 생성(하위호환 유지) — lisbon~madeira:100 [PASS] 구형식 파싱·억제 · 같은 날 이어붙여 신형식 승격 — 100|lisbon~madeira;sevilla~london [PASS] ParseInto 신형식 복원(day·lane 집합) — day=100 n=2 [PASS] ParseInto 빈 키 → day -1 · 빈 목록 [PASS] 구세이브 로드 → seaContactKey ""(가산 필드 기본값) — seaContactKey='' [PASS] 손상 세이브 방어(null → "") · ParseInto(null) 안전 ── 교역 정보 표시(시세 배지 · 평균 매입가) [PASS] PricePct 편차·0분모 방어(실 함수 호출) — 85/100=-15 115/100=15 120/0=0 [PASS] PriceTier 등급 경계(−15/+15 포함 · 실 함수 호출) — 85→-1 86→0 115→1 114→0 [PASS] 가중평균 매입가(10@20 + 10@30 → 25 · 수량 20) — 수량 20 · 평균 25닢 [PASS] 3차 매입 누적 가중(+5@46 → 29 · 수량 25) — 수량 25 · 평균 29닢 [PASS] 판매 후 평균가 보존(부분) · 전량 판매 시 엔트리 제거 — 부분 후 5@300 · 전량 후 평균 0 [PASS] 구세이브(avgCost 필드 부재) 로드 → 평균 0 · 이후 실매입이 새 단가로 시작 — 로드 평균 0 · 실매입 후 50닢/수량 10 ── 주점 타항구 시세 소문(실가격 유도 · 참 정보) [PASS] 시세 소문 진실성: 반환 조합의 PriceTier가 ±15% 경계 밖 · 반환 등급과 일치(실 함수 재대조) — 마데이라·포도주 호가 54/기준 85 → 등급 -1(반환 -1) [PASS] 시세 소문 현지 제외: 어느 항구를 현지로 넣어도 반환 항구≠현지(32항구 전수) — 전수 통과 [PASS] 시세 소문 결정론: 동일 gs·동일 주 → 동일 (항구,상품,등급) — 1차 madeira/wine/-1 · 2차 madeira/wine/-1 [PASS] 시세 소문 다른 주(1~8주): 시작점 변화 허용·매 주 반환이 여전히 참 정보 — 8주 전수 진실 [PASS] 시세 소문 전역 Random 무소비(호출 전후 난수열 불변 · 주간 해시 결정론) ── 주점 소문 믹스(시세:문화권 ≈ 2:1 · 주간 해시 결정론) [PASS] 소문 믹스 강제 비율 ≈ 설정값 CultureRumorShare(0.34) — 강제 1207/3328 = 0.363 (기대 0.34±0.06) [PASS] 소문 믹스 양측 노출: 시세·문화권 슬롯 모두 104주 중 1회 이상(문화권 flavor 부활) — 시세 68주 · 문화권 36주 [PASS] 소문 믹스 결정론: 동일 (주,항구) 재호출 동일 — 20주×전 항구 전수 동일 [PASS] 소문 믹스 전역 Random 무소비(주간 해시 결정론) ── 해도 가독성(라벨 슬롯 · 미탐험 포그) [PASS] 라벨 슬롯: 근접 2점 → 상이 슬롯(겹침 회피) — [0,1] [PASS] 라벨 슬롯: 원거리 2점 → 둘 다 기본 슬롯0 — [0,0] [PASS] 라벨 슬롯: 런던·브리스틀·안트베르펜 3개 상이 슬롯(사용자 지적 겹침 해소) — 런던0 브리스틀1 안트베르펜2 [PASS] 포그: 288셀(24×12) — 288 [PASS] 포그: 측량 셀 투명 · 미측량 셀 불투명 — A=False B=True [PASS] 포그: 현재 셀 항상 투명(측량 기록 없어도 자기 셀은 보임) — cur=83 [PASS] 포그: 신규 게임 대부분 안개(탐험 재미 · ≥250/288) — 286/288 안개 [PASS] 포그: curCell 범위 밖(−1) 안전 · 측량 셀만 걷힘 [PASS] CellOf 왕복: 288셀 중심좌표 → 정확한 셀 인덱스 [PASS] CellOf 경계 클램프([0,287] · 과대입력 안전) — c0=0 c1=287 c2=287 [PASS] 해도 탭: 반경 안(항구0 중심) → 0 선택 [PASS] 해도 탭: 반경 내 2항구 → 더 가까운 쪽(탭 −10: p0=14<p1=16 → 0) [PASS] 해도 탭: 반경 밖 → −1(침로로 낙하 · 팬/침로 불변) [PASS] 해도 탭: 포그(비가시) 항구는 −1(미탐험 정보 무유출 — 중심 정타여도 배제) [PASS] 해도 탭: 세비야 중심 로컬 → 세비야 인덱스(실좌표 왕복) — got=0 sev=0 ── 튜토리얼 게이트 리셋(설정 '항해 안내 다시보기') [PASS] 게이트 왕복: 전 게이트 Set→ResetGates→전부 해제 — 게이트 8개 전부 리셋 [PASS] 게이트 리셋 비침습: tut_* 만 해제 · 그 외 flags 보존 — 타 flags 보존=True · 게이트 해제=True [PASS] ClearFlag 안전·역연산: 없는 플래그 무해 · Set→Clear 왕복 성립 — Set 후 True · Clear 후 해제 True ── 항구 정보 카드·시설 메뉴(원정 교역 계획) [PASS] 시설 게이트: 기본 5시설 항상 존재(경제 규모 1~5 무관) [PASS] 시설 게이트: 게시판 경계 eco 2(없음)/3(있음) — eco2=False eco3=True [PASS] 시설 게이트: 왕궁 경계 eco 4(없음)/5(있음) — eco4=False eco5=True [PASS] 시설 게이트: 뒷골목 = {알제·튀니스}만(다른 항구 배제) [PASS] 시설 게이트: 32항구 전수 정합(게시판 eco≥3·왕궁 eco≥5·뒷골목 집합) [PASS] 특산품 조립: 1개(런던→모직물) · 2개(세비야→포도주, 올리브유) — 런던='모직물' 세비야='포도주, 올리브유' [PASS] 특산품 조립: 0개·null → '특산품 없음'(방어) [PASS] 거리→일수: 같은 좌표 0° → 0일 — d0=0.000 [PASS] 거리→일수: 각거리 대칭(A↔B) — 15.89=15.89 [PASS] 거리→일수: 6.0°/7.5노트 → 2일 · 반나절 미만 → 최소 1일 — DegPerDay=3.00 6.0°→2일 1.2°→1일 [PASS] 거리→일수: 0속도 방어(하한 0.5°/일 · 10°→20일) — VoyageDaysF(10,0)=20.0 [PASS] 거리→일수: HUD ETA와 동일 산술(단일 원천) ── 스토리 완주: 마테오 카브레라 (mateo) [PASS] mateo 대단원 도달 — 이벤트 19개 · 대사 92줄 · 최종 grand_finale_done [PASS] mateo 개인 엔딩 플래그 · 최종 명성 모험 1310/교역 120/전투 440 · 칭호 「명예 기사」 ── 북해 곁이야기(트라위 「지워진 채권」) 게이트 체인 [PASS] 트라위 3부작 존재 · 사이드(옵셔널) 표기 [PASS] 북해 3항구 배치(안트베르펜→런던→함부르크) — antwerp/london/hamburg [PASS] 게이트 체인 배선(setFlag→needFlag 연쇄 · 3화 이중 게이트) [PASS] 1화 발화(안트베르펜 입항 → truus_side1) [PASS] 1화 미완 → 2화 미발화(런던) [PASS] 1화 미완 → 3화 미발화(함부르크) [PASS] 1화 완료 → 2화 발화(런던 → truus_side2) [PASS] 2화 미완 → 3화 미발화(함부르크) [PASS] 3화 이중 게이트(벨라스코 미전개 → 함부르크 미발화) [PASS] 벨라스코 전개 후 → 3화 발화(함부르크 → truus_side3) [PASS] 1화 명성 임계 미달 → 미발화(안트베르펜) — total 249 < 250 [PASS] 순차 완주(1→2→3화 순서 발화 · 3화 종결 플래그) ── 레반트 곁이야기(미리암 「기울어진 저울」) 게이트 체인 [PASS] 미리암 3부작 존재 · 사이드(옵셔널) 표기 [PASS] 레반트 3항구 배치(이스탄불→이즈미르→알렉산드리아) — istanbul/izmir/alexandria [PASS] 게이트 체인 배선(setFlag→needFlag 연쇄 · 3화 이중 게이트) [PASS] 1화 발화(이스탄불 입항 → miriam_side1) [PASS] 1화 미완 → 2화 미발화(이즈미르) [PASS] 1화 미완 → 3화 미발화(알렉산드리아) [PASS] 1화 완료 → 2화 발화(이즈미르 → miriam_side2) [PASS] 2화 미완 → 3화 미발화(알렉산드리아) [PASS] 3화 이중 게이트(벨라스코 미전개 → 알렉산드리아 미발화) [PASS] 벨라스코 전개 후 → 3화 발화(알렉산드리아 → miriam_side3) [PASS] 1화 명성 임계 미달 → 미발화(이스탄불) — total 259 < 260 [PASS] 순차 완주(1→2→3화 순서 발화 · 3화 종결 플래그) ── 카리브 곁이야기(세이바 「심는 손」) 게이트 체인 [PASS] 세이바 3부작 존재 · 사이드(옵셔널) 표기 [PASS] 카리브 3항구 배치(아바나→산토도밍고→베라크루스) — havana/santodomingo/veracruz [PASS] 게이트 체인 배선(setFlag→needFlag 연쇄 · 3화 이중 게이트) [PASS] 1화 발화(아바나 입항 → seiba_side1) [PASS] 1화 미완 → 2화 미발화(산토도밍고) [PASS] 1화 미완 → 3화 미발화(베라크루스) [PASS] 1화 완료 → 2화 발화(산토도밍고 → seiba_side2) [PASS] 2화 미완 → 3화 미발화(베라크루스) [PASS] 3화 이중 게이트(벨라스코 미전개 → 베라크루스 미발화) [PASS] 벨라스코 전개 후 → 3화 발화(베라크루스 → seiba_side3) [PASS] 1화 명성 임계 미달 → 미발화(아바나) — total 279 < 280 [PASS] 순차 완주(1→2→3화 순서 발화 · 3화 종결 플래그) ── 은퇴 회고 & 세이브 라운드트립 [PASS] 은퇴 회고 생성 — 6줄 [PASS] 연대기 표(BuildChronicle) 10행·값 정확 — 일수='총 9,131일 · 25년' 항구='1 / 32곳' 자산='15,000닢' [PASS] 연대기 작위 행(칭호·서임 티어) — 「견습 선원」 · 서임 제독 [PASS] 연대기 미서임·사관 없음 표기 — 작위='「견습 선원」 · 미서임' 사관='없음' [PASS] 세이브→로드 왕복 ── 엔딩 칭호(EndingTitle 사다리) & 자발 은퇴 게이트 [PASS] 엔딩 칭호 기본 폴백(무업적) = 한 시대의 뱃사람 — 한 시대의 뱃사람 [PASS] 소금기: 명성 250(TitleTier1) 경계 ON — 소금기 밴 뱃사람 [PASS] 소금기: 명성 249 → 기본 폴백 — 한 시대의 뱃사람 [PASS] 소금기: 자산 25,000 경계 ON [PASS] 소금기: 자산 24,999 → 기본 폴백 [PASS] 다섯 바다: 총 명성 1500(TitleTier3) 경계 ON [PASS] 다섯 바다: 1499 → 소금기로 하강 [PASS] 해협의 사자: 전투 명성 800 & 최고 경계 ON [PASS] 해협의 사자: 전투 799 → 미달(소금기) [PASS] 해협의 사자: 전투 800이라도 교역이 더 높으면 사자 아님(다섯 바다) [PASS] 바다의 거상: 자산 100,000 경계 ON [PASS] 바다의 거상: 99,999 → 소금기로 하강 [PASS] 수평선 너머: 발견 완주(전 랜드마크) ON [PASS] 수평선 너머: 완주-1은 미완주(기본 폴백) [PASS] 우선순위: 발견 완주 > 대자산(거상) [PASS] 왕관의 대제독: 제독+자산 100,000 ON [PASS] 왕관의 대제독: 제독이라도 자산 99,999면 대제독 아님 [PASS] 우선순위: 복수 조건 전부 충족 → 최상위(왕관의 대제독) [PASS] 모든 칭호·맺음줄 비어있지 않음(대서/에피셋 안전) [PASS] 자발 은퇴: 신규 게임(day0·무플래그) 미노출(오탭 방지) [PASS] 자발 은퇴: 5년차 직전(day 1824) 미노출 [PASS] 자발 은퇴: 5년차(day 1825) 노출 [PASS] 자발 은퇴: 대단원 플래그면 day0라도 노출 [PASS] 자발 은퇴: null gs 방어(false) ── 회귀 검사(커버리지 공백 봉합) [PASS] 질병 온셋: 발병 성립 · 총 앓는 기간 5~9일 · 앓는 중 매일 사기 -2 — onset=True · 앓는날 8(기대 5~9) · 사기-2/일 True [PASS] 질병 온셋 결정론: 동일 입력 재호출 → 동일 sickDays·사기·경고 — sickDays 7=7 · morale 3=3 [PASS] 사무장 판매세: 미고용 30 · P1 25 · P2 20 · P3 15닢(기대 상수 대조) — none=30 p1=25 p2=20 p3=15 [PASS] 사무장 판매세 하한(가정 P6): PurserTaxRate(6)=1.5% 클램프 · 1000닢당 15닢(실 함수 호출) — p6Rate=0.015 tax=15 [PASS] 사관 로테이션: 풀 크기 ≥ 2(2후보 로테이션 전제) — L=16 [PASS] 사관 로테이션: 후보 인덱스 항상 [0, Officers.Length) (실 로직 호출) [PASS] 사관 로테이션: 두 후보 항상 상이(중복 카드 방지·실 로직 호출) [PASS] 손상 세이브 실왕복(Game.LoadGame 정규화): 사기100·배급2·작위4·질병0·칙명3 — morale=100 ration=2 court=4 sick=0 comm=3 [PASS] 나포 경계(=5): 편입 허용(실 게이트) · DraftCrew=minCrew · TotalCrew 보존 · 각 배≥1 — gate=True drafted=12/12 · TotalCrew 17→17 · 각배≥1 True [PASS] 나포 경계(=4): 편입 거부(실 게이트 false) — TotalCrew-minCrew=4 [PASS] 나포 함대 상한(4척): 선원 충분해도 편입 거부(실 게이트) — fleet=4 · 선원충분=True · 게이트=False [PASS] 나포 차출 하한: 각 배 최소 1 유지(crew 2·2, need 3 → drafted 2 · 각 배≥1) — drafted=2(기대 2) · 각배≥1 True · 함대 crew[1,1] [PASS] 칙명 손상 data: Progress 파싱 방어(false · 무예외) — threw=False progressed=False [PASS] 칙명 기한 초과: Complete 거부(false · 무예외 · 상태 불변) — threw=False completed=False kind=1 [PASS] 레이아웃: 간판 전 쌍 중심거리 ≥ SignW(비겹침, 실 좌표 참조) — 최소 244.4px (조선소~뒷골목) ≥ 176 [PASS] 레이아웃: 우하단 버튼 열 y간격 ≥ 버튼높이 + 갭(비겹침, 실 상수 참조) — 최소 간격 82 ≥ 높이 74(갭 8) [PASS] 레이아웃: 사기 게이지 vs 망꾼 배너 — 수직 겹침 상태서 수평 분리 유지(실 상수 참조) — 게이지 x[14,374] y[-184,-138] · 배너 x[400,1520] y[-240,-156] · vOverlap=True hClear=True [PASS] 레이아웃: 교역 행 라벨 밴드 우변 < 버튼 밴드 좌변(비겹침, 실 상수 참조) — 라벨 우변 836 < 버튼 좌변 852 (여백 16px, 행폭 1410) [PASS] 레이아웃: 주점 Row B 전 상태 수평 비겹침 + 패널 내 포함(실 함수 참조) — 최소 인접간격 16px · 최소 가장자리 여백 34px [PASS] 레이아웃: 주점 Row A 상단 < Row B 하단(수직 비겹침, 실 상수 참조) — Row A 상단 110 < Row B 하단 124 (이격 14px) [PASS] Safe Area: 전체화면 입력 → 인셋 0(데스크톱/에디터 회귀 0, 실 함수 호출) — min (0.00, 0.00) max (1.00, 1.00) [PASS] Safe Area: 노치/홈바 인셋 → 앵커 정규화 정확·[0,1] 유지(실 함수 호출) — min (0.04, 0.04) max (1.00, 1.00) (기대 minx 0.038 miny 0.042) [PASS] Safe Area: 화면 크기 0 → 전체화면 폴백(방어) — min (0.00, 0.00) max (1.00, 1.00) [PASS] 레이아웃: 교역 행 매수↔매도 버튼 간격 ≥ 28px(오탭 방지, 실 상수 참조) — 간격 28px (b10 우변 308 − s1 좌변 280) · 라벨우변 836 < 버튼좌변 852 ── 선장 성장 축 (행동 기반 능력 성장 · DKW2 패리티) [PASS] 성장 0: 유효 능력치 = CharacterDef 기본치(7종 전부) — 통솔 74/74 · 항해술 92/92 · 검술 55/55 [PASS] 성장 0: 도주 실산식 비트 동일(EffectiveStat == 기본치 입력) — 0.9240 == 0.9240 [PASS] 성장 0: 포격·백병 입력 스탯 = 기본치(통솔·검술) [PASS] 성장 반영: 항해술 +10 → 유효치 +10 · 도주 chance +0.02(결정론) — 유효 102 · chance 0.924→0.944 [PASS] 마일스톤 경계: N-1 미달(=0) · N 도달(=1) · N+1 유지(=1) · 2N(=2) — 0/1/1/2 [PASS] 마일스톤 증분·상한 클램프: +1/+0/+1 후 거대 카운터 → cap(15) 정확 — Δ 1/0/1/13 · 최종 15/15 [PASS] 마일스톤 방어: 상한 후 무증가 · 잘못된 인덱스/step≤0 → 0 [PASS] 지식 훅 성장 0: 보고 포상 = raw(비트 동일) — 441 == 441 [PASS] 지식 훅 성장 10: 보고 포상 +10% 정확(성장분 비례 · 회계 일치) — 485 == 485 (raw 441) [PASS] 지식 훅 상한: 만렙(+15) 보고 증분 = +15% ≤ 밴드 — 10000→11500(+15%) [PASS] 지식 훅 측량 판매: 성장 0 = 원액 · 성장 5 → +5% — 1080 · +5% 1134 [PASS] 매력 훅 고용가: 성장 0 = 기본가(비트 동일) · 성장 10 → -5% — 성장0 2400/2400 · 성장10 2280 [PASS] 매력 훅 고용가 하한 방어: 과대 성장도 상한(15)분 할인(0.925×) · 항상 ≥ 80% 기본가 — 상한할인 2220 · 하한 1920 [PASS] 매력 훅: TryHireOfficer가 할인가 차감(회계 일치) — 차감 2280(기대 2280) [PASS] 매력 훅 한턱: 성장 0 = +10(비트 동일) · 임계 = +11 · 임계 미만 = +10 — 0:10 · 임계:11 · 미만:10 [PASS] 구세이브 로드: 성장 필드 부재 → 성장 0 · 유효치=기본치 · boardingWins 0 — 성장0=True · 유효=기본=True · boardingWins=0 [PASS] 손상 세이브 실왕복(Game.LoadGame): 성장분 0..15 클램프(write-back) · boardingWins ≥0 — 통솔성장 15 · 항해성장 0 · boardingWins 0 [PASS] 손상 세이브: statGrowth 길이 불일치 → 7칸 재생성(무예외) — len=7 [PASS] 교역 카운터: CharmTrades회 성사 → tradesDone 정확 증가 · 매력 +1 — tradesDone 0→8 · 매력성장 1 ── 항구 보급 요약(감사 [A]) + 날씨 다양성(안개·시간대 톤 · 감사 [B]) [PASS] 보급 요약: 하루 소모 미러 = 실 DailyTick 소모(배급 절약/정상/포식 교차검증, 실코드 호출) — 3단계 전부 정수 일치 [PASS] 보급 요약: 물 부족·적재 만재 시 경고색 · 넉넉하면 평색(순수 함수 직접 호출) — 부족=True 넉넉=False 만재=True [PASS] 보급 요약: 잔여 일수 경계 — 5일치(경고)/6일치(평색) — 경계=True 초과=False [PASS] 레이아웃: 항구 상태바 2줄 헤더 내 수직 포함 + 힌트 리본 비겹침(실 상수 참조) — 헤더[-96,-10] 윗줄상단 -15 아랫줄하단 -91 · 리본상단 -102 [PASS] 안개: FogIntensity 결정론(동일 입력 → 동일 출력) — 0.0000 == 0.0000 [PASS] 안개: FogIntensity 게이트 — 열대·극·강풍 → 0 · 출력 [0,1](실코드 스윕) — 열대=True 극=True 강풍=True 범위OK=True 최대 0.88 [PASS] 안개: 약풍·온대 위도에서 안개 발생일이 존재(결정론 · dead 아님) — 발생일수 102/240 (첫날 0) · 최대강도 0.88 [PASS] 시간대 톤: 정오 무틴트 · 밤 남색(b>r) · 노을 주홍(r>b)(순수 함수 직접 호출) — 정오α 0.00 · 밤(a 0.22 b 0.34>r 0.10) · 노을(a 0.10 r 0.95>b 0.52) [PASS] 시간대 톤: wrap(밤→새벽) 알파 연속 + 전 구간 α∈[0,Cap](실코드 스윕) — 경계 0.122≈0.120 · 최대α 0.220 ≤ 0.22 [PASS] 날씨 합성: 폭풍 지배(둘 다 0) · 안개 최대 → 정확히 Cap · 상한 준수(순수 함수 직접 호출) — 폭풍(f 0 t 0) · 안개최대 f 0.220(Cap 0.22) [PASS] 날씨 합성: 안개↑→시간대색↓ · 무풍↑→안개↓(이중 해무 방지, 순수 함수 직접 호출) — 시간대색 안개0 0.200→안개1 0.060 · 안개 무풍0 0.132→무풍1 0.053 ── 랜드마크 발견 삽화(도감 썸네일·발견 카드) [PASS] 발견 삽화 24종 생성 + PNG↔meta 페어링(결번 0) — png 24/24 · meta 24 · orphan 0 [PASS] 도감 삽화 밴드 비겹침(썸<글<텍 · 이름<태그좌 · note<행폭 · 썸높≤행높) — 썸우 174<글 184 · 글우 236<텍 250 · 이름우 835<태그좌 846 · note우 1080<행폭 1110 [PASS] 발견 카드 삽화 밴드 비겹침(삽<텍열 · 텍열≤카드폭 · 삽높≤카드높) — 삽우 186<텍 206 · 텍우 656≤카드폭 680 · 삽높 100≤카드높 250 === 결과: 307 PASS · 0 FAIL ===
검은 수평선 · macOS 스탠드얼론 빌드 2026-07-12 04:52 build result=Succeeded · size=125MB · errors=0 · warnings=0 · out=/Users/dev/WinterVoyage/TheVoyage/dist/mac/BlackHorizon.app 검은 수평선 · Android APK 빌드 (IL2CPP/ARM64) 2026-07-12 04:53 build result=Succeeded · size=391MB · errors=0 · warnings=0 · out=/Users/dev/WinterVoyage/TheVoyage/dist/android/BlackHorizon.apk
산출물: dist/mac/BlackHorizon.app (117MB, Apple Silicon). 러너: BlackHorizon/Assets/Editor/QARunner.cs
— RunPlaythrough(로직 검증) / BuildMac(빌드). 재실행은 Unity 배치모드 -executeMethod.