← Back to the full chapter
Lesson

7. Serve recommendations that can be replayed

Model demand, separate the causal response, and optimise within supported limits.

2 min readApplied extensionUpdated
Read source ↗

A daily batch job is usually enough for a first posted-price system. Version the response model, policy configuration and price application separately. Use an API when operators or downstream systems need a consistent recommendation contract.

{
  "request_id": "price-2026-10-08-001",
  "sku_id": "SKU-17",
  "market_id": "STORE-3",
  "decision_at": "2026-10-08T08:00:00+05:30",
  "horizon_hours": 24,
  "currency": "INR",
  "current_price_minor": 10000,
  "cost_snapshot_id": "cost-17-v4",
  "inventory_snapshot_id": "stock-3-v21",
  "policy_version": "pricing-v2"
}

Validate currency, positive prices, horizon, timestamps and snapshot ownership. Resolve approved prices and constraints on the server, so the caller cannot relax them. Money uses integer minor units, with currency-specific rules defined in the contract.

Return decision_id, status (recommended, fallback, review_required), recommended or null price, validity interval, supported alternatives, expected contribution, uncertainty semantics, reason codes, model version, policy version and snapshot versions. A demand interval must state its unit, horizon and nominal coverage. A mean-lift confidence interval must state the comparison policy and inference method. Avoid a generic percentage called “confidence.”

Save the pre-decision feature snapshot, grid, eliminated candidates and reasons, response estimates, selected price, assignment probability, operator override, applied price and actual exposure. Join purchases and matured returns using decision_id plus the decision unit and time interval. Log the action actually taken even if an operator overrides it, and keep the original experimental assignment for the planned analysis. Make retries idempotent, and stop an expired recommendation from overwriting a newer price.

Save a pending application record before delivery. Tie the idempotency key to the exact price, unit, interval and release, then check the current price and version atomically when applying it. Reject a changed or expired state instead of overwriting a newer decision, and reconcile an unknown delivery result before retrying. The response's alternatives are diagnostic, not permission to apply a price that failed a gate.

An operator override may have an unknown selection probability. Mark it clearly, and do not reuse the original randomisation probability as the override's propensity. These records can stay in an intention-to-treat analysis, but offline evaluation of actual actions needs a justified way to handle them.

Monitor stale inputs, cost changes, price application failures, recommendation/application gaps, abstention rate, supported-action coverage, price oscillation, margin-floor breaches and latency. Once outcomes mature, add profit, bias, demand interval coverage, returns, repeat purchase and complaints. Show outcome completeness by decision cohort, so a recent cohort does not look more profitable just because its returns have not arrived.

Set named owners and triggers for rolling back to the approved fallback, such as a sudden margin drop, broken stock logging or too many constraint violations. Retraining is a reviewed response to evidence, not the automatic answer to every drift alert.

Something unclear or out of date? Suggest a correction ↗

Find your next idea

Loading local search…

Search is built from this edition. No account needed.