Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.kaireonai.com/llms.txt

Use this file to discover all available pages before exploring further.

This page is the operator-facing reference for every configurable field on every Decision Flow node. For each knob you get:
  • Purpose — what the field controls.
  • Engine behavior — exactly what the engine does when this value changes.
  • Verification — how to prove the field had an effect (test script, doc cross-link, or live API call).
Where a field is covered by an automated test we link the script. Where it’s only documented or only tested end-to-end through the Studio UI we say so honestly.

Phase 1 — Narrow

Inventory node

FieldPurposeEngine behaviorVerification
scopeConstrain candidate set by category / subcategory / explicit offer list.WHERE clause on the Offer query in pipeline-runner.ts case "inventory".T1 baseline recommend.
categoryIds[]Restrict to specific categories.category_id IN (...) predicate.T1, T2.
subCategoryIds[]Restrict to specific sub-categories.sub_category_id IN (...) predicate.T1.
offerIds[]Whitelist specific offers (bypasses category scope).offer.id IN (...) predicate.UI-tested.
includeStatuses[]Default ["active"]; allow staged/test offers in development flows.Status filter on the Offer query.UI-tested.

Match Creatives node

FieldPurposeEngine behaviorVerification
requireCreativeDrop candidates with no creative.Filter candidate.creative != null after Inventory.T1.
placementMatchModeexact keeps only creatives whose placementId matches request; any keeps wildcard creatives too; none skips placement filtering.Branches in case "match_creatives" (pipeline-runner.ts:780).T1, T8 (atomic coupling).

Enrich node

FieldPurposeEngine behaviorVerification
Auto-enrich (implicit)All active SchemaJoins with autoEnrich=true merge their joined customer rows before any Enrich node runs.autoEnrichFromJoins() runs at line 590 of pipeline-runner.ts before nodes execute.T14.
sources[].schemaIdManually attach a schema that isn’t auto-joined, or override a join with custom fields.Reads the schema’s table, queries by lookupKey, prefixes results.T14.
sources[].lookupKeyFK column to use (default customer_id).WHERE "<lookupKey>" = $customerId.UI-tested.
sources[].fields[]Restrict to subset of columns (perf optimization).Generates a SELECT col1, col2 ... projection.UI-tested.
sources[].prefixNamespace prefix in enrichedData (default customer).Output keys become <prefix>.<field>.UI-tested.
sources[].cacheTtlSecondsPer-source Redis cache TTL.Cache key enrich:<tenantId>:<schemaId>:<customerId>:<fields> — TTL set per source.Logged but not asserted in tests.
sources[].optionalSoft-fail when the schema or row is missing.try/catch around the lookup; missing data → field not set instead of throwing.UI-tested.
sources[].multiRow + aggregationRoll up multiple rows (e.g. last-30-day transactions) into one summary.Triggers GROUP BY + aggregation function per field.UI-tested.
transforms[]Apply record-level transforms after lookup (hash, mask_pii, expression, etc.).Each transform mutates the enrichedData map in-place.UI-tested.

Qualify node

FieldPurposeEngine behaviorVerification
mode = "all"Apply every globally-scoped active QualificationRule.Filters rules.filter(isGlobalRule).T2.
mode = "selected"Apply only the explicit rule IDs (any scope — operator chose them).rules.filter(r => ruleIdSet.has(r.id)).T2.
mode = "none"Skip qualification entirely.Early break.UI-tested.
qualificationRuleIds[]The set of rule IDs when mode = "selected".Consumed at line 879 of pipeline-runner.ts.T2.
logic (AND/OR groups)Combinator tree for selected rules.Recursively evaluates groups; AND requires all-pass, OR requires any-pass.Logged finding — not exercised in current proofs.

Contact Policy node

FieldPurposeEngine behaviorVerification
modeSame shape as Qualify: all (every active policy), selected (explicit list), none (skip).filterByContactPolicies() consumes the filtered policy set.T3 (cooldown), T4 (frequency cap), T5 (category suppression), T6 (DNC), T7 (metric_condition).
contactPolicyIds[]Explicit policy list when mode = "selected".Same dispatch as Qualify.T3–T7.

Filter node

FieldPurposeEngine behaviorVerification
conditions[].fieldPath into enrichedData or candidate attributes.Resolved via dot-path lookup.UI-tested.
conditions[].operatorOne of 13: eq, neq, gt, gte, lt, lte, in, not_in, contains, starts_with, regex, is_null, is_not_null.Pure boolean evaluation per candidate.UI-tested.
conditions[].valueRHS of comparison.Type-checked at evaluation.UI-tested.
combinatorAND requires all conditions true; OR requires any.Boolean reduction.UI-tested.

Conditional (split) node

FieldPurposeEngine behaviorVerification
conditions[] + combinatorSame syntax as Filter — the predicate that decides which branch to take.Evaluated per candidate.UI-tested.
trueBranchFlowIdSub-flow to execute for matching candidates.Loaded + executed via executePipelineV2 (subject to depth/cycle guards).UI-tested.
falseBranchFlowIdSub-flow for non-matching candidates.Same dispatch. Optional.UI-tested.
keepNonMatchingWhen false (default), non-matching candidates are filtered out. When true, they pass through to the next node.Branches the rejection path.UI-tested.
labelOperator-facing label rendered on the canvas.Display-only.n/a.

Phase 2 — Score & Rank

Score node — the most-configurable node in the flow

See Scoring Strategies for the operator-facing decision guide. Reference of every field:
FieldPurposeEngine behaviorVerification
methodThe base strategy: priority_weighted, propensity, or formula (PRIE).Routes through one of three branches in pipeline-runner.ts:1734-1995.T15 (3 sub-cases).
modelKey / defaultModelWhich AlgorithmModel the propensity and formula methods use when no adaptation data is present.Resolved by resolveScoreConfig() then loaded via prisma.algorithmModel.findFirst.T15 sub-case 2.
formulaInline PRIE weights {propensityWeight, relevanceWeight, impactWeight, emphasisWeight}. Must sum to 1.0.Used in case "formula" line 1879. Profile mapping overrides if strategyProfileId set.T15 sub-case 3.
overrides[] (per-scope ML model)Pick a different AlgorithmModel per (offer, channel), per offer, per category, per subcategory, or per channel.resolveModelForCandidate() walks the priority chain (default: offer_channel → offer → category → subcategory → channel → default).T15 sub-case 8.
overridePriority[]Override the default scope priority.Drives the loop in scoring-resolver.ts:70.UI-tested.
championChallenger.enabledActivate A/B model routing.selectVariantPersistent() deterministically routes per customerId based on weights.UI-tested (Critical path #147).
championChallenger.champion.{modelKey, weight}The currently-serving model.Weight gets normalized against challengers.UI-tested.
championChallenger.challengers[]Models being tested at fractional traffic.Weighted choice via FNV-1a hash of customerId + ":cc".UI-tested.
channelOverrides[] (deprecated, kept for compat)Per-channel different method/model/formula.resolveScoreConfig() consults this list first when channelId matches.T15 sub-case 6.
strategyProfileIdDefault RankingProfile whose weights map to PRIE (conversion → Wp, recency → Wr, margin → Wi, fairness → We).Replaces formula field when set; resolution at line 1857.T15 sub-cases 4–5.
strategyOverrides[]First-match-wins profile selector by productType / category / channel.Loops at line 1842; first matching scope wins.T15 sub-case 7.
shadowModelKeys[]Models that ALSO score every candidate in parallel — recorded only, NEVER affects ranking.applyShadowScoring() runs after the active path.UI-tested.

Engine-wide settings that affect Score behavior

These live on Tenant.settings and apply to every flow’s Score node:
SettingDefaultPurpose
propensitySmoothingWeight10Blend weight when offer has 1–49 outcomes — blends learned rate with category/global prior.
propensityScoreFloor0.05Minimum propensity component. Prevents starvation when an offer has 50+ negative-only outcomes (raw positiveRate = 0). Clamped to [0, 0.5]. Verified live in T20 Test C — Platinum scored 0.0 before the floor and 0.05 after.
modelMaturityThreshold100Below this evidence count, scores are scaled down (maturity ramp).
rankingInfluencersEnabledtrueWhen true, sibling-offer outcomes influence a candidate’s score via category propagation.

Algorithm models (referenced from modelKey)

AlgorithmModel.modelTypeMathEngine entry-pointVerification
scorecardWeighted rules table → sigmoid normalizationscoreScorecardT16.
bayesianNaive Bayes with Laplace smoothingscoreBayesianT16.
logistic_regressionWeighted sum → sigmoidscoreLogisticRegressionT16.
gradient_boosted (operator alias: AGB)Tree-ensemble margin → sigmoidscoreGradientBoostedT16.
thompson_banditBeta-Bernoulli posterior samplingscoreThompsonT16.
epsilon_greedyε-greedy exploitation with decayscoreEpsilonGreedyT16.
online_learnerOnline SGD on numeric featuresscoreOnlineT16.
neural_cfTwo-tower embeddings → MLP → sigmoidscoreNeuralCFT16.
external_endpointHTTP POST to operator-hosted servicescoreOfferSetExternal (async path)UI-tested.
onnx_importedONNX runtime inferencescoreOnnxImported (async path)UI-tested.

Optimize node (deprecated — folded into Score’s strategyProfileId)

The Optimize node is kept for back-compat and now acts as a passthrough. Use Score.strategyProfileId instead.

Rank node

FieldPurposeEngine behaviorVerification
method = "topN"Take the top N by score.Sort by score descending, take first N.T1, T2.
method = "diversity"Greedy diversity selector — penalizes consecutive same-category picks.MMR-style selection at line 2202.UI-tested.
method = "round_robin"Round-robin across categories until N reached.Round-robin pointer scan.UI-tested.
method = "explore_exploit"ε-greedy mix of top-N with random N′.Uses explorationRate to decide per-slot.UI-tested.
maxCandidatesThe N in top-N.Result slice length.T1.
maxPerCategoryDiversity cap.Hard ceiling — drop further candidates from a category once cap is hit.UI-tested.
maxPerChannelSame idea per channel.Same enforcement.UI-tested.
explorationRateε in explore_exploit.Decides exploit-vs-explore per slot.UI-tested.

Group node

FieldPurposeEngine behaviorVerification
allocationStrategy = "optimal"Hungarian (Kuhn-Munkres) global assignment — per-offer uniqueness across placements.allocateOptimal() builds the cost matrix, runs Munkres.T1, T8 (atomic coupling cascade), T9 (vs greedy).
allocationStrategy = "greedy"Slot-by-slot best score per placement. Faster, can repeat the same offer across placements.allocateGreedy().T9.
allocationStrategy = "priority_fill"Fill slots in priority order until done.allocatePriorityFill().UI-tested.
placements[] (optional override)A/B-test slot counts without forking the flow. When absent, slots derive from request.placements[] × Placement.maxSlots.At line 720, the override merges with placement catalog.T1.
allowPartialDeprecated — channel coupling is the supported lever.No-op.n/a.

Phase 3 — Output

Compute node — runs in any phase

The compute executor doesn’t care about phase. What changes is which candidate set the formulas evaluate against. See Computed Values for formula syntax.
FieldPurposeEngine behaviorVerification
overrides[]Per-candidate computed fields named to OVERRIDE an existing category-level computed field.Evaluates formula then writes to candidate.personalization[name], replacing any prior value.T13.
extras[]Per-candidate computed fields with new names (don’t collide with category-level fields).Same as overrides but appends.T13.
transforms[]Record-level transforms on personalization after computed fields fire — e.g. mask_pii, cast_type.Applied to the merged personalization map.UI-tested.
Placement choice (T19):
  • Phase 1 (after Enrich) → applies to every candidate that survived Qualify + Contact Policy. Use this when a downstream node (Score, Filter) needs to read the computed value.
  • Phase 3 (after Rank/Group) → applies only to the final top-K. Use this for render-only personalization (greetings, computed credit limits, conditional CTA text).

Set Properties node

FieldPurposeEngine behaviorVerification
properties[].keyProperty name surfaced in response under properties.{key}.Direct assignment.UI-tested.
properties[].value (literal)Static value.Written verbatim.UI-tested.
properties[].formulaComputed value via the same formula engine compute uses.evaluateFormula() over the candidate’s context.UI-tested.

Response node

FieldPurposeEngine behaviorVerification
includeDebugTraceInclude the full per-stage trace in the response body.Adds trace to the response.T2, T3, all trace-bearing tests.
responseFormat = "standard"Default flat shape.One offer per response entry.T1, T10.
responseFormat = "grouped"Group by placement.Wrap entries under placements.{placementId}.T1, T8.

Cross-phase nodes

Call Flow node

FieldPurposeEngine behaviorVerification
flowIdTarget DecisionFlow.id.Loads the target flow, runs via executePipelineV2.UI-tested.
passContextForward request attributes + enrichedData to sub-flow.When true, sub-flow inherits parent context.UI-tested.
mergeMode = "replace"Sub-flow result replaces parent candidates.Standard.UI-tested.
mergeMode = "append"Sub-flow result is unioned with parent candidates.Concatenation.UI-tested.
optionalSoft-fail if sub-flow missing.Try/catch around dispatch.UI-tested.

Extension Point node

FieldPurposeEngine behaviorVerification
hookNameLifecycle stage: pre_score / score_override / post_rank. Operator-facing label only — runtime treats them identically.Recorded in trace; visible in flow editor.T17.
label, descriptionOperator-facing strings.Display-only.n/a.
configuredGate. When false, node is a no-op (safe placeholder in templates).Early return at pipeline-runner.ts:2533.T17 case 1.a.
subFlowIdDecisionFlow.id of the linked sub-flow.Loaded with status: "active" filter + V2 check.T17 cases 2.a–3.b.
Implicit depth cap (2)DoS hardening — sub-flows can nest at most 2 levels deep.Skip at line 2542.T17 case 2.c.
Implicit cycle breakA → B → A loops are detected via visitedFlowIds set.Skip at line 2547.T17 case 3.a.

Verification index

Each test below is reproducible from a clean checkout. Scripts run via jiti so they don’t need the Next.js dev server.
TestScriptWhat it locks
T13platform/scripts/test-compute-personalization.mts22 compute-node personalization patterns through the live evaluateFormula.
T15platform/scripts/proof-scoring-e2e.mtsAll three scoring methods + channelOverrides + strategyOverrides + resolveModelForCandidate routing — through live engine helpers.
T16platform/scripts/proof-algorithms-e2e.mtsEach of 10 algorithm types loads + scores against the same input.
T17platform/scripts/proof-extension-point.mtsAll 7 gate/guard branches of the extension_point dispatcher.
Coverage gaps tagged “UI-tested” above are exercised through the studio recommendation preview + decision-traces UI but don’t yet have committed scripts. Adding them is the operator-friendly way to close the audit — each row gets a script + a doc cross-link.