> ## 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.

# Goal-seek Ranking

> W5.2 proportional control law that adjusts offer score multipliers to hit period targets. Default off; gated by tenantSettings.aiAnalyzerSettings.ranking.goalSeekEnabled.

## What it does

Given a per-offer **period target** + **current actual** + **fraction
of period elapsed**, goal-seek projects end-of-period delivery and
applies a score multiplier to push toward the target.

```
projectedEndOfPeriod = currentActual / fractionOfPeriodElapsed
gap = target − projectedEndOfPeriod
adjustmentFraction = clamp(kp · (gap / target), −maxAdj, +maxAdj)
multiplier = clamp(1 + adjustmentFraction, 0.5, 1.5)
```

* `kp` = proportional gain (default `1.0`)
* `maxAdjustmentPct` = signed clamp (default `0.5`)
* The final multiplier is bounded `[0.5, 1.5]` so goal-seek can rotate
  rank order but cannot overwhelm or eliminate scores.

The control law is intentionally simple — proportional, no integral,
no derivative. Anti-windup comes from the multiplier clamp, not from
a separate accumulator.

## Configuration

Two layers, mirroring pacing:

1. **Tenant flag**:
   ```json theme={null}
   { "ranking": { "goalSeekEnabled": true } }
   ```
2. **Per-offer goal config** on the Offer record under `goal`:
   ```json theme={null}
   {
     "goal": {
       "target": 5000,
       "currentActual": 1200,
       "fractionOfPeriodElapsed": 0.4,
       "kp": 1.0,
       "maxAdjustmentPct": 0.5
     }
   }
   ```

`kp` and `maxAdjustmentPct` are optional with the defaults shown.

## When goal-seek applies vs no-ops

* Flag off → wire never runs.
* Flag on AND offer has well-formed `goal.target / currentActual /
  fractionOfPeriodElapsed` (all numeric) → multiplier applied,
  `goalSeekAgg.applied++`.
* Flag on AND offer's goal config is missing or has wrong types →
  `goalSeekAgg.awaitingConfig++`. Score is preserved.

## What gets logged

Per batch run with the flag on:

```
INFO goalseek.applied {
  runId, tenantId,
  applied, awaitingConfig
}
```

When the flag is off, **nothing** is logged for goal-seek.

## Honest limits

* **No automatic period tracking.** The wire reads `currentActual` +
  `fractionOfPeriodElapsed` straight off the offer. Operators must
  refresh those fields on a cadence that matches their target's
  granularity (e.g., a midnight cron for daily targets).
* **No multi-objective coupling.** Goal-seek runs **after** pacing
  (when both flags are on), so the multipliers compound. Operators
  who want either-or semantics should enable only one flag at a
  time.
* **Per-offer only.** Cross-offer goals (e.g., "\$10k portfolio
  daily revenue") are not modeled in V1.

## Operational checklist

* Set `kp` conservatively at first (1.0 is the floor). Aggressive
  gains can produce oscillation when paired with the bandit.
* `maxAdjustmentPct = 0.3` (instead of the default 0.5) is a safer
  starting cap when running goal-seek alongside other multipliers.
* Watch the projected vs actual delta in the offer's daily report. If
  goal-seek is driving but the offer never reaches target, raise `kp`
  or check whether decisioning gates are upstream blockers that
  goal-seek cannot influence.

## Cross-references

* [`ranking-budget-pacing.mdx`](/decisioning/ranking-budget-pacing) — same wire location; pacing applies BEFORE goal-seek when both flags are on.
* [`ranking-exp3ix.mdx`](/decisioning/ranking-exp3ix)
* [`ranking-lagrangian.mdx`](/decisioning/ranking-lagrangian)
