4.7 KiB
장수 행동 모듈 프로토콜
packages/logic/src/actionModules/는 ref의 iAction을 그대로 복사한 범용
interface가 아니라, 실제 core2026 실행 경계만 타입으로 표현합니다. 계산
hook, 우선순위 trigger, 의미 이벤트는 서로 다른 실행 계약입니다.
세 가지 실행 계약
| 계약 | core2026 경계 | 실행 의미 |
|---|---|---|
| 순차 계산 hook | GeneralActionPipeline |
ref의 General::getActionList() 순서대로 값을 fold합니다. |
| 우선순위 trigger | triggers/core.ts, triggers/general.ts, 전투 trigger |
priority, 삽입 순서와 unique ID 중복 제거를 보존한 뒤 fire합니다. |
| 의미 이벤트 | actionModules/events.ts |
닫힌 이벤트별 payload와 context를 동기적으로 순회합니다. |
priority trigger를 의미 이벤트로 바꾸거나, 의미 이벤트를 TriggerCaller로
감싸지 않습니다. 두 경로는 정렬과 중복 제거 의미가 다릅니다.
ref 순서와 소유권
정기턴은 loadActionModuleBundle()에서, 전투 시뮬레이터는 같은
createRefOrderedActionStack() factory에서 제품용 action stack을
조립합니다. 순서는 다음과 같습니다.
- 국가 타입
- 관직
- 내정 특기
- 전투 특기
- 성격
- 병종
- 계승 버프
- 시나리오 효과
- 아이템
RefOrderedActionStack의 readonly unique-symbol brand는 임의 배열을 제품용
표준 stack으로 오인하지 않게 하는 shadow type입니다. 모든 slot을 명시하는
factory에서만 이 brand를 만들 수 있으며, 예약턴 runtime env에도 spread하지
않고 그대로 전달합니다. 현재 시나리오 효과 runtime module은 이식되지 않아
해당 slot은 명시적으로 null입니다. 따라서 이 brand는 순서와 slot 소유권을
증명하며, 시나리오 효과 구현 완료를 뜻하지 않습니다.
닫힌 의미 이벤트
GeneralActionEventPayloadMap이 허용하는 이벤트와 payload의 단일
source입니다. 현재 이벤트는 장비 구매·판매, 계략 성공, 도시 점령입니다.
- 이벤트는
createGeneralActionEvent()만 생성합니다. private unique-symbol brand 때문에 객체 literal로 위조할 수 없습니다. GeneralActionEventContext<K>가 이벤트별 필수 능력을 정합니다. 예를 들어 판매는 RNG와 연월, 도시 점령은 RNG가 없으면 compile되지 않습니다.- leaf module은
eventHandlers에 처리하는 이벤트 key만 선언합니다. - trait, 병종과 item catalog 같은 합성 router만 내부
handleEvent를 구현합니다. 두 capability는never를 사용한 상호 배타적 union이라 한 module에서 동시에 선언할 수 없습니다. - 새 문자열 action name,
phase,aux: Record<string, unknown>를 범용 우회로로 추가하지 않습니다.
새 이벤트를 추가할 때는 payload map과 context 조건을 먼저 추가한 뒤, 실제 producer와 필요한 handler만 연결합니다. 존재하지 않는 handler 종류를 interface에 선행 추가하지 않습니다.
저장과 RNG 경계
의미 이벤트는 producer가 가진 객체를 동기적으로 수정합니다. producer는 이벤트 전후의 ref mutation 순서를 그대로 유지한 뒤 기존 effect/flush 경계에 결과를 전달합니다.
- 장비 판매는 판매 대금 반영 → 판매 이벤트 → 슬롯 제거 순서입니다.
- 도기 판매의 2분기는 ref
choice([gold, rice])와 같이 index 0이 금, index 1이 쌀입니다. - 도시 점령은 점령 도시의 수비국 장수 전원을 입력 순서로 호출한 뒤 국가
멸망 손실을 계산합니다. 이벤트 handler와 멸망 손실은 같은
ConquerCityRNG 객체를 이어 씁니다. - 계략 성공 아이템 소비는
consumeOnStrategySuccess라는 명시 capability로 선언하며 다른 임의 action 이름과 공유하지 않습니다.
검증 경계
actionModuleEvents.test.ts는 표준 순서, 이벤트 brand와 잘못된 context의
compile 실패를 검증합니다. itemActionEvents.test.ts는 도기 분기와
연차 경계, 충차·환약 초기 충전, 계략 성공 소비를 검증합니다.
warAftermath.test.ts는 도시 점령 대상과 공유 RNG 소비 순서를 검증합니다.
ref↔core 실제 명령 차등은
turnCommandGeneralMatrix.integration.test.ts의 도기 판매 fixture가
담당합니다.