DEV Community

Aleksander Sekowski
Aleksander Sekowski

Posted on

ARTF Explained: How a Live Bid Request Gets Patched Before the Auction

On 14 October 2026, Prebid previewed an auction model where ad servers bid into Prebid Server instead of the other way around (AdExchanger). More demand paths still end in the same artifact: a JSON bid request the SSP forwards to buyers. IAB Tech Lab's ARTF v1.0 milestone adds a parallel change: containerized agents beside that stream, proposing patches before anyone bids. When our own Prebid remedies write-up talks about bid requests gaining new hops, ARTF is one of the hops that mutates the object in flight.

The Agentic Real Time Framework is not a replacement for OpenRTB. It is a gRPC extension point around it. The host keeps the auction; the agent proposes deltas; the orchestrator accepts or rejects each mutation on its own. Transport success and auction validity are different questions.

What the host sends: envelope, lifecycle, and applicable intents

An ARTF call is an RTBRequest, not a bare bid request. Protobuf JSON carries at least:

  • lifecycle: which programmatic auction stage this call belongs to (publisher bid request, bid response, and the other stages the IAB auction definition names).
  • id: the extension-point request id for this container invocation (not the OpenRTB bidrequest.id).
  • bid_request: the OpenRTB payload as protobuf JSON (enum names, bool semantics, and field casing the reference stack expects).
  • bid_response: present only on stages where a response exists to patch.
  • tmax: milliseconds the host will wait for mutations, including network latency.

The host also advertises which mutation intents are legal at this lifecycle via ext.applicable_intents. An agent that proposes BID_SHADE on a publisher bid request is speaking to a bid that does not exist yet. The gRPC stack can still return OK; the mutation is wrong for the stage. That class of mismatch is artf.mutation.intent_not_applicable. A missing or empty applicable-intent list is its own failure mode: artf.intents.missing when the host never told the agent what it is allowed to do.

Lifecycle must be explicit. An unspecified enum value fails artf.lifecycle.unspecified even when the nested OpenRTB object looks fine. Operators who only monitor container health see green while the envelope contract is empty.

How mutations patch the auction object

The agent answers with RTBResponse: an envelope id, optional metadata, and a mutations array. Each mutation is four ideas wired together:

  1. Intent (why): ACTIVATE_DEALS, ADJUST_DEAL_FLOOR, ADD_METRICS, and the rest of the v1.0 intent catalog.
  2. Operation (how): add, replace, or remove in OpenRTB terms.
  3. Path (where): a semantic path to a business entity, not a JSON pointer. Deal floors target /imp/{imp id}/pmp/deals/{deal id}, not a loose /imp/imp-1 when the intent needs a deal node.
  4. Value (what): a protobuf oneof. ACTIVATE_DEALS carries ids; ADJUST_BID carries adjust_bid. Only one arm may be set. Copy the wrong constructor from another intent and the RPC still succeeds while intent and payload disagree.

Paths are resolved against the request the host actually attached, including impression ids and deal ids on that snapshot. A path to deal-premium when the request only lists deal-standard is artf.mutation.deal_unknown. Omitting path entirely is artf.mutation.path_missing. ARTF evaluates mutations independently: there is no transaction across the array. One accepted floor change and one rejected segment add is normal; the orchestrator forwards whatever subset it trusts.

After acceptance, the host merges patches into the OpenRTB object it will send downstream. That merged object can introduce fields illegal for the exchange's dated snapshot (for example metrics shapes OpenRTB 2.6-202606 rejects). The agent never saw the failure if you stopped at gRPC.

What an RPC OK leaves unchecked

GetMutations returning OK means the container responded in time with a parseable protobuf JSON document. It does not mean:

  • The response id matches the RTBRequest.id the orchestrator issued.
  • Every mutation's intent appears in applicable_intents for this lifecycle.
  • Every semantic path resolves on the carried bid request or bid response.
  • Applied mutations yield OpenRTB the exchange validates on its version train.

When the carried bid request is missing or not an object, the envelope is artf.request_unusable regardless of mutation quality. That is the failure mode for cached envelopes, wrong-key lookups, and LLM outputs that wrap the auction in an extra JSON layer.

Hosts need three passes: validate the request envelope and embedded OpenRTB, validate the mutation set against lifecycle and paths, then apply accepted mutations and revalidate OpenRTB so field damage shows up on the object buyers will see. The ARTF simulator runs apply-then-revalidate in a browser; the longer walkthrough is ARTF mutations and bid request validation.

How you catch it

An implementation that lets a model emit ARTF envelopes and mutation lists still has to check them against the wire contract. rtblint (cargo install rtblint, npm install rtblint-core, MCP rtblint-mcp) owns that check: validate_artf_request, validate_artf_response, and response validation with apply for post-patch OpenRTB. The same rules run in CI, MCP tools an agent can call on its own output, and gRPC validators on openadtech.rtblint.v1. rtblint is independent of IAB Tech Lab and of AAO; the spec does not require it, and nothing in v1.0 replaces pass three before you forward.

Example CLI after a container returns mutations:

$ rtblint validate --type artf-response --request rtb-request.json --apply rtb-response.json
FAILED (OpenRTB 2.6-202606 ARTF mutation set): …
Enter fullscreen mode Exit fullscreen mode

Where to go next

  • ARTF explained for lifecycle and intent vocabulary on one page.
  • Rule reference index under rtblint docs for envelope, mutation, and apply-time OpenRTB findings.
  • RTBlint blog for dated OpenRTB trains and agentic stacks next to ARTF.

Production ARTF means production patch bugs. gRPC OK is transport; the auction object is still pass three.

Top comments (0)