정책 룰이란?
정책 룰(Policy Rule) 은 조건 → 액션의 쌍입니다. 입력 facts가 조건을 만족하면 룰의 액션이 실행됩니다. 룰은 우선순위 순서 (0이 가장 높은 우선순위)로 평가됩니다.조건 문법
조건은SINGLE과 GROUP 두 노드 타입의 트리 구조입니다.
SINGLE 조건
단일 fact를 값과 비교하는 leaf 노드:GROUP 조건
자식 조건을AND 또는 OR로 결합하는 branch 노드:
연산자
IN / NOT_IN의 경우 호환 타입 열은 검사 대상 fact의 타입(STRING 또는 NUMBER)을 가리킵니다. 제공하는 value는 리스트 자체이며, 그 valueType은 LIST_STRING 또는 LIST_NUMBER입니다.값 타입
중첩 조건 예시
(customer_tier = "VIP" AND payment_amount >= 100000) OR region IN ["KR", "JP"]
위 예시에서
customer_tier, region, payment_amount는 사용자 정의 fact로 Fact Definitions에 등록하는 것이 좋습니다. 등록 전에 참조해도 되며 — LexQ는 미등록 키를 거부하지 않고 비차단 경고로 알립니다 — 등록하면 타입 검증과 requirements analyzer가 활성화됩니다. 기본 제공 시스템 fact는 user_id, user_tags 두 개뿐입니다.액션 타입
LexQ 엔진의 액션은 도메인 중립 원시(primitive) 입니다. 엔진은 숫자와 구조만 봅니다 — 커머스 / 핀테크 / 보험 / 특정 비즈니스 모델을 가정하지 않습니다. 도메인 의미는 fact 이름과 integration 페이로드에 담깁니다.MUTATE_FACT — Percentage
payment_amount를 10% 감소:
payment_amount가 200,000이면 → 180,000으로 감소. 변화량(-20,000)은 generatedVariables의 payment_amount__delta로 노출됩니다.
연산자(Operator)
MUTATE_FACT — Fixed Amount
MUTATE_FACT — 반올림(Rounding)
기본적으로 calculator 출력은 무손실(lossless) 정밀도로 보존됩니다. 고정 자릿수가 필요할 때만 선택적rounding 필드를 사용하세요.
rounding.scale은 [0, 16] 범위의 정수. rounding.mode는 HALF_UP(default), HALF_DOWN, HALF_EVEN, FLOOR, CEILING, DOWN, UP 중 하나. rounding을 생략하면 무손실 정밀도가 유지됩니다 — 가능하면 엔진이 아니라 다운스트림(예: 통화 표시 시점)에서 반올림하세요.
INCREMENT_FACT — Percentage
payment_amount의 1%를 total_point에 적립:
payment_amount가 100,000이면 → total_point가 1,000 증가. 증분량은 generatedVariables의 total_point__delta로 노출됩니다.
INCREMENT_FACT는 엔진 내부 fact 변경만 수행합니다. 외부 시스템(예: 포인트 서비스) 동기화가 필요하면 동일 룰 안에서 [INCREMENT_FACT, EMIT_EVENT] 체인으로 구성하세요. 엔진은 INCREMENT_FACT 대신 외부 시스템을 호출하지 않습니다 — 이는 엔진 상태와 외부 상태 사이의 audit-grade 분리를 보존하기 위함입니다.INCREMENT_FACT — Fixed Amount
EMIT_EVENT
외부 integration에 generic 이벤트 페이로드를 발행합니다. 엔진은integrationId와 비어있지 않은 eventPayload 맵의 존재만 검증합니다 — 페이로드 구조는 integration provider의 책임입니다.
couponId, ticketId, claimId 등)는 integration provider가 라우팅합니다. 이로써 EMIT_EVENT는 진정한 generic primitive가 됩니다 — 쿠폰 발행, 티켓 생성, 보험 청구 제출 등 어떤 이벤트성 외부 호출에도 사용할 수 있습니다.
EMIT_NOTIFICATION
외부 integration을 통해 알림을 발송합니다.targetVar는 수신자 fact를 지정합니다 (예: phone_number, email, device_token). notificationPayload는 채널, 템플릿, 변수 매핑을 integration provider에 전달 — 엔진은 이 키들을 해석하지 않습니다.
BLOCK — 요청 차단
SET_FACT — Output Variable
ADD_TAG
targetVar를 생략하면 user_tags가 기본값입니다.
EMIT_WEBHOOK — Basic
payloadTemplate 없이 사용하면 엔진은 모든 input/output facts를 요청 본문으로 전송합니다 (시스템 변수 제외).
EMIT_WEBHOOK — With Payload Template
payloadTemplate로 요청 본문을 커스터마이징하세요. 템플릿 변수는 실행 시점에 치환됩니다.
사용 가능한 템플릿 변수
Slack은
{"text": "..."}, Discord는 {"content": "..."} 형식이 필요합니다. 각 플랫폼이 기대하는 형식에 맞춰 payloadTemplate을 사용하세요.생성 변수 (Generated Variables)
변경된 facts와 별도로, 엔진은 액션별 변화 정보를generatedVariables로 노출합니다:
한 룰에서 여러 액션이 같은 fact를 변경하면
__delta는 누적 변화량을 보고합니다. 액션별 스냅샷은 audit drill-down용으로 executionTraces에 보관됩니다.
Mutex — 룰 단위 충돌 해소
한 버전 내에서 룰들은 mutex 그룹에 속할 수 있으며, 이를 통해 매칭되는 룰 중 몇 개를 발화시킬지 제어합니다.mutexMode가 EXCLUSIVE이면 winning 룰 하나만 발화합니다. MAX_N이면 우선순위 순서로 최대 mutexLimit개의 룰이 발화합니다. 발화하지 못한 다른 매칭 룰은 Decision Trace에 status BLOCKED + reason MUTEX_PRIORITY_LOST 또는 MUTEX_LIMIT_REACHED로 기록됩니다 (Decision Trace 참조).
Decision Trace
룰 평가 결과는 모두 decision trace 엔트리로 기록되어 해당 룰이 발화했는지 / 왜 그렇게 결정됐는지를 설명합니다. 이는 LexQ의 audit-grade 추론 영역의 핵심입니다 — 모든 결과는 특정 status와 reason code로 추적할 수 있습니다. decision trace 엔트리는 두 분류 필드를 가집니다:status— 결과의 상위 분류reasonCode— 그 분류 안에서의 구체적 사유
DecisionStatus
DecisionReasonCode
Status × ReasonCode 매핑
“왜 내 룰이 발화하지 않았지?”를 디버깅할 때 decision trace는 두 단계로 답을 줍니다 —
status는 어떤 분류의 필터링이 룰을 제거했는지 알려주고, reasonCode는 정확히 어떤 검증이 룰을 거부했는지 알려줍니다.완전한 룰 예시
다음 단계
Fact Definitions
룰이 기대하는 입력 변수를 정의하세요.
Dry Run
배포 전에 룰을 테스트하세요.

