# The ARTF Intent Cheat Sheet Every OpenRTB Bid Ops Engineer Needs

> Source: <https://dev.to/aleksuix/the-artf-intent-cheat-sheet-every-openrtb-bid-ops-engineer-needs-2n17>
> Published: 2026-10-28 00:25:06+00:00

On 12 August 2026 IAB Tech Lab posted that [ARTF v1.0 is FINAL](https://iabtechlab.com/a-milestone-for-the-agentic-advertising-ecosystem/) and ready for production bidstreams. That is the week exit codes on container health checks start standing in for OpenRTB conformance. The Agentic Real Time Framework still ends on the same object buyers parse: a [bid request](https://rtblint.org/docs/openrtb/bid-request/) or bid response inside an `RTBRequest` / `RTBResponse` envelope. Agents return patches, not replacements. Each patch line carries an **intent** (why), an **operation** (add, replace, remove), a **semantic path** (which auction entity), and a **value oneof** (`ids`, `adjust_deal`, `adjust_bid`, `metrics`, or `content_data`). If you wire agents without a sheet that maps intent to path and payload, you will green-light RPCs that leave deals on impressions that never carried them or shade bids that do not exist yet.

This table is for engineers who own the orchestrator: SSP curators, exchange sidecars, DSP shading hooks. It is not a substitute for the [ARTF explained guide](https://rtblint.org/guides/artf-explained/); it is the bookmark you open when a mutation JSON lands in logs.

ARTF splits work by **lifecycle**. Request-stage intents run at `LIFECYCLE_PUBLISHER_BID_REQUEST` on the publisher ticket. Response-stage intents run at `LIFECYCLE_DSP_BID_RESPONSE` when a bid object exists. The host also sends `applicable_intents`: an ACL of what the agent is allowed to propose. An intent outside that list is policy, not syntax.

Semantic paths are not JSON pointers. They name business entities with stable segments such as `/imp/imp-1/pmp/deals/deal-premium` or `/seatbid/seat-1/bid/bid-42`. RTBlint resolves paths the same way the reference rules do: `imp/{id}`, `imp/{id}/pmp/deals/{deal id}` (or the shorter `.../deals/{deal id}` form), `/user/data/segment`, and `/seatbid/{seat}/bid/{bid id}`.

| Intent | Lifecycle | Example semantic path | Payload oneof | OpenRTB field the host applies | 
|---|---|---|---|---|
| `ACTIVATE_SEGMENTS` | Publisher bid request | `/user/data/segment` | `ids` | `user.data[].segment` | 
| `ACTIVATE_DEALS` | Publisher bid request | `/imp/imp-1/pmp/deals/deal-premium` | `ids` | Deal id added under `imp.pmp.deals[]` | 
| `SUPPRESS_DEALS` | Publisher bid request | `/imp/imp-1` (remove op) | `ids` | Named deals removed from `imp.pmp.deals[]` | 
| `ADJUST_DEAL_FLOOR` | Publisher bid request | `/imp/imp-1/pmp/deals/deal-premium` | `adjust_deal` | `deals[].bidfloor` | 
| `ADJUST_DEAL_MARGIN` | Publisher bid request | `/imp/imp-1/pmp/deals/deal-premium` | `adjust_deal` | No OpenRTB 2.6 field (orchestrator only) | 
| `ADD_METRICS` | Publisher bid request | `/imp/imp-1` | `metrics` | `imp.metric[]` | 
| `BID_SHADE` | DSP bid response | `/seatbid/seat-1/bid/bid-42` | `adjust_bid` | `seatbid[].bid[].price` | 
| `ADD_CIDS` | Publisher bid request | `/user/data/segment` | `ids` or`content_data` | `data[].cids` (OpenRTB 2.6-202505+) | 

One row worth reading twice: **`ADD_CIDS` on an exchange pinned to an earlier 2.6 snapshot**. The intent is legal ARTF. The member may not exist on the wire version the host runs, so apply either no-ops or produces a field downstream DSPs reject. Version negotiation sits outside the mutation list; the envelope does not carry a dated snapshot string for the agent to read.

**`ADJUST_DEAL_MARGIN` with a perfect protobuf JSON mutation.** Floor and margin share the `adjust_deal` oneof on the wire, but margin is not part of the OpenRTB Deal object. The orchestrator is supposed to apply margin in commercial logic the bid object never sees. Static validation warns with [`artf.mutation.no_openrtb_target`](https://rtblint.org/docs/rule-reference/artf-mutation-no_openrtb_target/). Treating that warning as success means you billed for a mutation that never changed what buyers parse.

**`ACTIVATE_DEALS` carrying `adjust_bid`.** Copy-paste from a DSP shading template is the common source. Protobuf JSON parsing succeeds; gRPC returns OK; pass two fails because [`artf.mutation.payload_intent_mismatch`](https://rtblint.org/docs/rule-reference/artf-mutation-payload_intent_mismatch/) binds `ACTIVATE_DEALS` to `ids`, not `adjust_bid`. The curator thought it activated a deal. The exchange got an illegal oneof.

**`BID_SHADE` at publisher request lifecycle.** Shading needs a bid. `LIFECYCLE_PUBLISHER_BID_REQUEST` has no `bid_response` payload to target. That is [`artf.mutation.intent_not_applicable`](https://rtblint.org/docs/rule-reference/artf-mutation-intent_not_applicable/) plus missing target payload, not a floor tweak you can forward anyway.

**`ADD_METRICS` with `Metric.value` as a string.** ARTF can accept the mutation object; OpenRTB expects a numeric `value`. Framework v1.0 does not require a third pass after apply, so the failure shows up only if you revalidate the bid request the host will fan out. The longer walkthrough of apply-then-revalidate is in [ARTF mutations and bid request validation](https://rtblint.org/blog/artf-mutations-bid-request-validation/).

**Paths that look like JSON pointers.** `/imp/imp-1/pmp/deals/deal-premium/bidfloor` is not a documented semantic reference. You get [`artf.mutation.path_unrecognized`](https://rtblint.org/docs/rule-reference/artf-mutation-path_unrecognized/) even when the deal id exists on the ticket. Deal floors use `ADJUST_DEAL_FLOOR` on the deal path, not a fake leaf segment.

I run three passes on every ARTF hop: envelope and carried OpenRTB as protobuf JSON, each mutation against lifecycle, `applicable_intents`, path resolution, and intent-specific oneof members, then apply accepted mutations and revalidate OpenRTB so field damage appears on the object buyers will see.

The [ARTF simulator](https://rtblint.org/demo/artf/) runs the same engine in a browser: paste an `RTBRequest`, paste mutations, watch apply-then-revalidate. CLI:

``` bash
$ rtblint validate --type artf-request rtb-request.json
$ rtblint validate --type artf-response --request rtb-request.json rtb-response.json
$ rtblint validate --type artf-response --apply \
    --request rtb-request.json rtb-response.json
```

MCP tools `validate_artf_request` and `validate_artf_response` (with `apply` when you need post-patch OpenRTB) let an agent implementation call the check on its own output. The RPC can still return OK; the wire contract inside the envelope does not move. **rtblint** (`cargo install rtblint`, `npm install rtblint-core`, MCP `rtblint-mcp`) is the deterministic check on that object and mutation set. It is independent of IAB Tech Lab and of AAO; the spec does not require it, and nothing in v1.0 replaces pass two before you forward.

Production ARTF means production mutation bugs. gRPC success is transport; OpenRTB validity is still what decides fill.
