feat: NPC 판단 당시 합성 정책을 기록하고 조회한다

This commit is contained in:
2026-09-16 09:21:50 +00:00
parent c9fe204c94
commit 292ca7662d
16 changed files with 216 additions and 40 deletions
@@ -1,3 +1,4 @@
import { snapshotEffectiveAiPolicy } from './effectivePolicy.js';
import { observeAiRng, type AiDecisionTraceObserver, type AiTraceStep } from './trace.js';
import type {
City,
@@ -216,7 +217,8 @@ export class GeneralAI {
): AiCommandCandidate | null {
if (!this.onDecisionTrace) return choose();
this.tracePhase = phase;
this.trace({ kind: 'DECISION_START', reservedAction: reserved.action });
this.trace({ kind: 'DECISION_START', reservedAction: reserved.action,
effectivePolicy: snapshotEffectiveAiPolicy(this.generalPolicy, this.nationPolicy) });
try {
const result = choose();
this.trace({ kind: 'DECISION_END', action: result?.action ?? null, reason: result?.reason ?? null });
@@ -0,0 +1,37 @@
import type { AutorunGeneralPolicy, AutorunNationPolicy } from '../policies.js';
/** 이미 합성된 정책만 복사한다. can() 재평가, world/meta 복사나 RNG 호출은 하지 않는다. */
export const snapshotEffectiveAiPolicy = (general: AutorunGeneralPolicy, nation: AutorunNationPolicy) => ({
schemaVersion: 1 as const,
general: { priority: [...general.priority], flags: { ...general.flags } },
nation: {
priority: [...nation.priority],
flags: { ...nation.flags },
values: {
reqNationGold: nation.reqNationGold,
reqNationRice: nation.reqNationRice,
reqHumanWarUrgentGold: nation.reqHumanWarUrgentGold,
reqHumanWarUrgentRice: nation.reqHumanWarUrgentRice,
reqHumanWarRecommandGold: nation.reqHumanWarRecommandGold,
reqHumanWarRecommandRice: nation.reqHumanWarRecommandRice,
reqHumanDevelGold: nation.reqHumanDevelGold,
reqHumanDevelRice: nation.reqHumanDevelRice,
reqNpcWarGold: nation.reqNpcWarGold,
reqNpcWarRice: nation.reqNpcWarRice,
reqNpcDevelGold: nation.reqNpcDevelGold,
reqNpcDevelRice: nation.reqNpcDevelRice,
minimumResourceActionAmount: nation.minimumResourceActionAmount,
maximumResourceActionAmount: nation.maximumResourceActionAmount,
minNpcWarLeadership: nation.minNpcWarLeadership,
minWarCrew: nation.minWarCrew,
minNpcRecruitCityPopulation: nation.minNpcRecruitCityPopulation,
safeRecruitCityPopulationRatio: nation.safeRecruitCityPopulationRatio,
properWarTrainAtmos: nation.properWarTrainAtmos,
cureThreshold: nation.cureThreshold,
},
combatForce: Object.fromEntries(Object.entries(nation.combatForce).map(([id, cities]) => [id, [...cities]])),
supportForce: [...nation.supportForce],
developForce: [...nation.developForce],
},
});
export type EffectiveAiPolicy = ReturnType<typeof snapshotEffectiveAiPolicy>;
@@ -1,3 +1,4 @@
import type { EffectiveAiPolicy } from './effectivePolicy.js';
import type { RandUtil } from '@sammo-ts/common';
/** 원문 meta/seed/임의 객체를 받지 않는 관측 계약. 내부 후보 조건은 별도 계측으로 확장한다. */
@@ -22,7 +23,7 @@ export type AiExecutionAttempt = {
};
export type AiTraceStep =
| AiExecutionAttempt
| { kind: 'DECISION_START'; reservedAction: string }
| { kind: 'DECISION_START'; reservedAction: string; effectivePolicy?: EffectiveAiPolicy }
| { kind: 'DECISION_END'; action: string | null; reason: string | null }
| { kind: 'DECISION_ERROR' }
| { kind: 'PROCEDURE_START'; procedure: string }