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.
What it does
When a multi-turn negotiation session reaches status: "accepted", its
finalProposal represents the agreed terms (discount, term, bundle,
final price). Apply-mode promotes that proposal into the realtime
/api/v1/recommend response so downstream callers see the negotiated
terms alongside the next-best-action ranking.
Each ranked decision is decorated with one of:
appliedNegotiation: { sessionId, proposal } — every gate passed; the
caller can present the negotiated terms.
appliedNegotiationReject: { sessionId, reason } — a session existed
but a gate blocked the apply (e.g., daily cap exceeded, regulator
review still required, kill switch tripped).
When no session exists for a given (tenant, customer, offer), the
decision is returned unchanged.
Configuration
{
"aiAnalyzerSettings": {
"negotiation": {
"applyModeEnabled": true,
"regulatorReviewCleared": true,
"dailyApplyCap": 50,
"killSwitchTenant": false,
"killSwitchGlobal": false,
"recentValidationFailureRate": 0.0,
"autoKillThreshold": 0.2
}
}
}
| Field | Default | Meaning |
|---|
applyModeEnabled | false | Master flag. When off, the wire short-circuits with zero I/O — no latency cost for non-opt-in tenants. |
regulatorReviewCleared | false | Only flip to true after the 30-day eval-harness run shows zero violations across the negotiation eval set. Without this flag every apply rejects with regulator_review_required. |
dailyApplyCap | 50 | Hard cap on auto-applies per tenant per day (UTC). |
killSwitchTenant | false | Per-tenant emergency stop. Trips immediately when set to true. |
killSwitchGlobal | false | Org-wide emergency stop, set centrally. |
recentValidationFailureRate | 0 | Rolling 0..1 ratio. When ≥ autoKillThreshold the gate auto-trips. |
autoKillThreshold | 0.2 | Threshold for the auto-trip above. |
Response shape
{
"decisions": [
{
"offerId": "off_premium_savings",
"rank": 1,
"score": 0.84,
"appliedNegotiation": {
"sessionId": "sess_5f0a…",
"proposal": {
"rationale": "loyal customer, 24mo tenure",
"discountPct": 12,
"termMonths": 12,
"finalPriceCents": 8800,
"currency": "USD"
}
}
},
{
"offerId": "off_basic",
"rank": 2,
"score": 0.73,
"appliedNegotiationReject": {
"sessionId": "sess_a1b2…",
"reason": "apply_budget_exceeded"
}
}
],
"meta": {
"negotiationApply": { "applied": 1, "rejected": 1 }
}
}
meta.negotiationApply is omitted when the wire is in noOp (flag off
or no relevant sessions found).
Reject reasons
reason | When |
|---|
apply_mode_disabled | The flag is off (rare — short-circuits earlier; surfaces only in audit rows). |
offer_not_negotiable | Offer.negotiable !== true. |
kill_switch_tripped | One of the three kill switches fired. The audit row’s changes.reject.source says which: tenant, global, or auto_error_rate. |
regulator_review_required | regulatorReviewCleared is false. |
apply_budget_exceeded | Today’s apply count ≥ dailyApplyCap. |
guardrail_violations | The session’s finalProposal re-validation failed. The audit row carries the violation list. |
guardrails_missing | Offer is negotiable=true but has no negotiationGuardrails configured — fail-CLOSED. |
Audit trail
Every apply and every reject writes one AuditLog row with:
action: "negotiate_apply_realtime" (apply) or "negotiate_apply_realtime_reject" (reject).
entityType: "negotiation_session", entityId: the session id.
changes: { sessionId, applied, proposal | reject }.
The route also runs appliesUsedToday from a count of these rows, so
the audit chain is the source of truth for daily-cap accounting.
Failure modes — fail-CLOSED
| Condition | Behavior |
|---|
tenantSettings lookup throws | Wire stays OFF; warn-level log surfaces the lookup failure; recommend response unchanged. |
| Offer / session lookup throws | Wire degrades to noOp; warn-level log surfaces it; recommend response unchanged. |
AuditLog.count throws | appliesUsedToday returns Number.MAX_SAFE_INTEGER so the daily-cap gate trips and every apply rejects with apply_budget_exceeded. Cap fails-CLOSED — an outage cannot silently lift the limit. Surfaces at error severity. |
Apply-row AuditLog.create throws | Logged at error (compliance teeth) — the apply decoration is still returned to the caller, but the absence of the audit row is escalated for reconciliation. |
Reject-row AuditLog.create throws | Logged at warn — informational. |
| Wire helper throws | The route’s try/catch returns the recommend response without decoration; the apply-mode failure never breaks ranking. |
Honest limits
-
Concurrency under-counting.
appliesUsedToday is read-once + per-call increment in memory; the audit row is written fire-and-forget. Two simultaneous /recommend calls for the same (tenant, day) can both read N and both apply up to cap, so the day total can exceed cap by (concurrency - 1) * applies_per_call before audit rows materialize. Acceptable for V1 because (a) the apply decoration is informational — no irreversible side effect — and (b) compliance retains the AuditLog rows for retroactive reconciliation. A Redis INCR with a TTL keyed negotiation:applies:{tenantId}:{YYYY-MM-DD} is on the roadmap and closes the gap.
-
appliesUsedToday cost. AuditLog.count is correct but slow under very high tenant volume. Same Redis follow-up addresses both this and #1.
-
Placements path not wired. The multi-placement
/recommend response shape is decorated separately. Today the apply-mode wire only runs on the single-flow + auto-resolve paths. Wiring placements is a small follow-up.
Operational checklist
- Enable
applyModeEnabled for one tenant first. Watch the meta.negotiationApply counter on /recommend responses and the AuditLog rows.
- Run the negotiation eval harness for 30 nights. When
zeroViolationClearance >= 0.95 for the full window, flip regulatorReviewCleared to true.
- A regression in any of:
solverFailed > 0 on the realtime arbitration log line, sustained kill_switch_tripped: { source: "auto_error_rate" } rejects, or AuditLog write failures at error severity → flip applyModeEnabled to false immediately. The wire is designed so flag-off is bit-identical to the pre-W15 response.
See also: Negotiation eval harness · Decision flows