Skip to content

Add batch decide action to rl.php for high-throughput Thompson Sampling lookups #43

@jjroelofs

Description

@jjroelofs

Background

Integration modules that apply Thompson Sampling client-side (for example, DXPR Builder's rl_dxpr_variant structural variant runtime) need a low-overhead decision endpoint. Routing decisions through a Drupal controller on every page view adds a full middleware stack (routing → access → CSRF → render → cache wrapper) just to read from rl_arm_data and call getThompsonScores().

The existing rl.php bare file already handles turn/reward beacons this way and bypasses the Drupal routing stack, booting the kernel once for a single service call. The same pattern makes sense for decisions.

Proposal

Add a third action, decide, to rl.php. Module-agnostic: the caller passes the experiment IDs it wants decisions for plus the arm count per experiment, and gets a JSON map of winning arm IDs back.

Request

  • action=decide
  • experiment_ids=rl_foo-abc,rl_foo-def,... (comma-separated)
  • arm_counts=2,3,... (parallel list of integers per experiment)

Response

{
  "decisions": {
    "rl_foo-abc": { "armId": "v1" },
    "rl_foo-def": { "armId": "v0" }
  }
}

Unknown, unregistered, or zero/one-arm experiments are omitted from the response so the caller can fall back to arm 0 (the default variant).

Implementation notes

  • Branches off the existing validation block so the turn/reward hot path is unchanged.
  • Uses the existing rl.experiment_registry and rl.experiment_manager services the kernel already exposes.
  • Returns {"decisions":{}} on malformed input or when rl.experiment_manager is unavailable.
  • Sends Cache-Control: no-store, private, max-age=0 so downstream caches never serve stale Thompson decisions.

Consumer

The immediate consumer is DXPR Builder's rl_dxpr_variant runtime (js/rl-variant-runtime.js), which posts this payload on every page load to resolve structural variant containers to a single winning arm before reveal. Previously it used a Drupal-routed endpoint; moving to rl.php cuts per-request middleware cost on pages that often carry multiple containers.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions