정책 규칙이란?
**정책 규칙(Policy Rule)**은 조건 → 액션의 쌍입니다. 입력 facts가 조건을 만족하면 규칙의 액션이 실행됩니다. 규칙은 우선순위 순서로 평가되며 1이 가장 높습니다. 한 버전 안에서 우선순위는 항상1…N 연속입니다. 새 규칙은 끝에 붙고, 순서를 바꾸면 전체가 다시 매겨집니다.
조건 문법
조건은SINGLE과 GROUP 두 노드 타입의 트리 구조입니다.
SINGLE 조건
단일 fact를 값과 비교하는 leaf 노드:GROUP 조건
자식 조건을AND 또는 OR로 결합하는 branch 노드:
연산자
IN / NOT_IN의 경우 호환 타입 열은 검사 대상 fact의 타입(STRING 또는 NUMBER)을 가리킵니다.
제공하는 value는 리스트 자체이며, 그 valueType은 LIST_STRING 또는 LIST_NUMBER입니다.값 타입
중첩 조건 예시
(customerTier = "VIP" AND paymentAmount >= 100000) OR region IN ["KR", "JP"]
위 예시에서
customerTier, region, paymentAmount는 사용자 정의 fact로 Fact Definitions에 등록하는 것이 좋습니다.
규칙이 읽기만 하는 키는 등록하지 않은 채로 참조해도 됩니다.
LexQ는 이런 미등록 키를 거부하지 않고 비차단 경고로 알립니다.
다만 등록해야 타입 검증과 값 제약이 동작합니다. 액션 대상은 먼저 등록해야 합니다(액션 타입 참고). 모든 테넌트에는 미리 등록된 fact가 있습니다(사전 등록 fact 참고).액션 타입
LexQ 엔진의 액션은 도메인에 종속되지 않는 원시 연산입니다. 엔진은 숫자와 구조만 볼 뿐 커머스, 핀테크, 보험 같은 특정 업종을 가정하지 않습니다. 업무 의미는 여러분이 정한 fact 이름에 담깁니다. 엔진은 외부 시스템을 호출하지 않습니다. fact를 바꾸고 결정을 기록할 뿐이며, 응답을 읽고 무엇을 할지는 호출한 쪽이 정합니다. 엔진 상태와 외부 상태를 분리해야 감사 추적이 성립하기 때문입니다.SET_FACT와 MUTATE_FACT의 targetVar는 등록된 fact여야 합니다. 등록되지 않은 키에 값을 쓰는 규칙은 저장과 발행이 ACT-032로 거절되므로, fact 정의에서 먼저 등록하세요.
isBlocked와 blockReason에는 BLOCK만 값을 씁니다. 두 키를 대상으로 쓰는 SET_FACT나 MUTATE_FACT가 있으면, 두 키가 등록된 fact인데도 규칙 저장과 발행이 ACT-033으로 거절됩니다.
MUTATE_FACT 파라미터
operator × method 매트릭스
DIV + AMOUNT 조합에서는 operand가 0 이면 안 됩니다.
targetVar와 refVar가 다를 때
refVar는 PERCENTAGE × 세 칸에서만 의미를 갖습니다.
다른 칸에서 지정하면 조용히 무시되지 않고 오류가 납니다.
AMOUNT에는 기준이라는 개념이 없고, MUL × PERCENTAGE는 배수 표기라서 기준을 읽지 않기 때문입니다.
계산 기준이 변경 대상과 다를 때 사용합니다.
loyaltyPoint += orderTotal × 5% 입니다. 적립 대상과 계산 기준이 서로 다른 fact 입니다. refVar를 생략하면 loyaltyPoint += loyaltyPoint × 5%가 되어 결과가 완전히 달라집니다.
MUTATE_FACT — 정률(Percentage)
paymentAmount를 10% 줄입니다. 통화 fact라면 아래 반올림 절을 함께 보세요.
MUTATE_FACT — 정액(Fixed Amount)
MUTATE_FACT — 반올림(Rounding)
rounding을 지정하지 않으면 결과가 무손실 정밀도로 유지됩니다. 통화 단위로 맞춰야 할 때 지정하세요.
mode 에는 UP, DOWN, CEILING, FLOOR, HALF_UP, HALF_DOWN, HALF_EVEN을 넣을 수 있습니다. 기본값은 HALF_UP 입니다.
SET_FACT — 값 대입
타입에 관계없이 값을 대입합니다. 요청에 없던 키에 값을 쓸 수 있는 유일한 액션입니다. 그래도targetVar는 등록된 fact여야 합니다.
SET_FACT는 덧붙이지 않고 통째로 대입합니다. LIST_STRING fact에 값을 누적하려면 현재 목록을 요청에 담아 보내고 새 목록 전체를 대입하세요.
산술 변경이 아니라 대입이므로 SET_FACT는 __delta를 만들지 않습니다. 같은 fact를 MUTATE_FACT도 바꾸면, 그 __delta에는 SET_FACT가 바꾼 몫도 들어갑니다(요청이 실행되는 순서 참고).
BLOCK — 거부 결정 기록
요청이 실행되는 순서
요청 하나는 두 단계로 실행됩니다.- 모든 규칙의 조건을 요청에 담긴 fact로 판정합니다. 어떤 액션보다도 먼저 일어나므로, 같은 요청에서 액션이 쓴 값을 조건은 보지 못합니다.
- 조건이 맞은 규칙의 액션을 우선순위 순서로 실행합니다. 각 액션은 앞 액션이 남긴 값 위에서 계산합니다. 앞 규칙의 액션이 남긴 값도 마찬가지입니다.
customerTier: "STAFF"와 paymentAmount: 100을 보내고 규칙 두 개가 맞으면 이렇게 됩니다.
규칙 2의 조건은 20이 아니라 요청 값 100을 보므로 여전히 맞습니다. 그 액션은 규칙 1이 남긴 20에 3을 곱합니다. 응답은
mutatedFacts.paymentAmount = 60, generatedVariables.paymentAmount__delta = -40입니다. __delta는 최종 값을 요청 값과 비교하므로 SET_FACT가 바꾼 몫도 들어갑니다.
두 규칙이 같은 EXCLUSIVE 상호 배타 그룹에 있으면 규칙 1만 발동하고 결과는 20입니다.
뒤 판단이 앞 결과에 따라 달라져야 하면, 그 결과를 담아 API를 한 번 더 호출하거나 두 액션을 한 규칙에 넣으세요.
생성 변수 (Generated Variables)
변경된 facts와 별도로, 엔진은 액션별 변화 정보를generatedVariables로 노출합니다:
여러 액션이 같은 fact를 바꾸면, 한 규칙 안이든 여러 규칙에 걸쳐서든
__delta는 요청 값과 최종 값의 차이를 보고합니다. 액션 하나하나의 스냅샷은 executionTraces에 남아, 감사 시 원인을 끝까지 되짚을 수 있습니다.
상호 배타 그룹(Mutex) — 규칙 간 충돌 해결
한 버전 안에서 규칙은 **상호 배타 그룹(mutex group)**에 속할 수 있습니다. 상호 배타 그룹은 조건이 맞는 규칙 중 몇 개를 발동시킬지 제어합니다.mutexMode가 EXCLUSIVE이면 경쟁에서 이긴 규칙 하나만 발동합니다.
MAX_N이면 우선순위 순서로 최대 mutexLimit개의 규칙이 발동합니다.
발동하지 못한 나머지 규칙은 Decision Trace에 status BLOCKED, reasonCode MUTEX_PRIORITY_LOST 또는 MUTEX_LIMIT_REACHED로 기록됩니다 (Decision Trace 참조).
Decision Trace
규칙 평가 결과는 모두 decision trace 엔트리로 기록되어 해당 규칙이 발동했는지, 왜 그렇게 결정됐는지를 설명합니다. LexQ가 모든 결정을 검증 가능하다고 말하는 근거가 여기에 있습니다. 어떤 결과든 status와 reasonCode 조합으로 되짚을 수 있습니다. decision trace 엔트리는 두 분류 필드를 가집니다:status: 결과의 상위 분류reasonCode: 그 분류 안에서의 구체적 사유
DecisionStatus
DecisionReasonCode
Status × ReasonCode 매핑
“왜 내 규칙이 발동하지 않았지?”를 디버깅할 때 decision trace는 두 단계로 답을 줍니다.
status는 어떤 분류의 필터링이 규칙을 제거했는지 알려주고, reasonCode는 정확히 어떤 검증이 규칙을 거부했는지 알려줍니다.CONDITION_MISMATCH에는 두 가지 사실이 섞여 있습니다. 조건이 거짓이었던 경우와, 조건을 평가할 수 없었던 경우(타입 불일치, 해소되지 않은 fact)입니다.
구체적인 사유는 reasonDetail에 담깁니다. 예를 들어 LIST_STRING fact에 평문 문자열이 들어오면 Evaluation error: FACT_TYPE_MISMATCH가 기록됩니다.
평가에 실패한 규칙이 있어도 실행 전체가 멈추지는 않으며 나머지 규칙은 정상 실행됩니다.완전한 규칙 예시
paymentAmount와 discountApplied를 fact로 등록하세요.
다음 단계
Fact Definitions
규칙이 기대하는 입력 변수를 정의하세요.
Dry Run
배포 전에 규칙을 테스트하세요.

