# Publisher-Stage ARTF With bid_response on the Envelope Stages the Agent Wrong

> Source: <https://dev.to/aleksuix/publisher-stage-artf-with-bidresponse-on-the-envelope-stages-the-agent-wrong-1mig>
> Published: 2026-09-18 00:01:47+00:00

An SSP-side ARTF host labels the extension point `LIFECYCLE_PUBLISHER_BID_REQUEST`, keeps yesterday's `bid_response` on the envelope for debugging, and forwards `ACTIVATE_DEALS` mutations against the publisher `bid_request`. gRPC returns OK. The agent believes no buyer has answered yet. The orchestrator is staring at a seatbid it never told the agent existed.

That is not a deal-activation bug in the agent. It is a reused envelope whose lifecycle name and its OpenRTB members disagree.

The IAB Tech Lab [Agentic Real Time Framework](https://iabtechlab.com/standards/artf/) (ARTF) puts a containerized agent beside an SSP, exchange, or DSP. The host sends an `RTBRequest` with a `lifecycle` value, a `tmax` budget in milliseconds, the OpenRTB object under mutation, and `applicable_intents`. The agent returns `Mutation` messages with semantic paths. The orchestrator applies what it accepts and only then forwards the auction.

Publisher-stage calls run before any DSP has answered. Response-stage calls expect a `bid_response` member when intents such as `BID_SHADE` need seat and bid ids. The lifecycle enum names the stage. It does not delete extra members you left on the JSON from an earlier hop.

`LIFECYCLE_PUBLISHER_BID_REQUEST` means the extension point sits on the outbound publisher request. No DSP answer belongs on that wire yet. If `bid_response` is present anyway, RTBlint reports [`artf.lifecycle.payload_unexpected`](https://rtblint.org/docs/rule-reference/artf-lifecycle-payload_unexpected/):

```
{
  "id": "ep-1",
  "tmax": 120,
  "lifecycle": "LIFECYCLE_PUBLISHER_BID_REQUEST",
  "bid_request": { "id": "a-1", "imp": [{ "id": "imp-1", "banner": { "w": 300, "h": 250 } }] },
  "bid_response": { "id": "a-1", "seatbid": [{ "seat": "dsp-1", "bid": [{ "id": "bid-abc", "impid": "imp-1", "price": 2.5 }] }] }
}
```

The envelope declares publisher bid request stage and carries a full `bid_response`. At that stage no DSP should have answered. The validator treats it as a warning, not a hard error, because a private host might deliberately pass prior context. For a default orchestrator, the warning is the point: the agent's model of where it sits in the auction is wrong even when protobuf JSON parses cleanly.

The inverse failure, response stage without `bid_response`, is [` artf.lifecycle.payload_mismatch`](https://rtblint.org/docs/rule-reference/artf-lifecycle-payload_mismatch/). That one blocks shading paths that need a bid id the envelope never included. Together they are the same contract: lifecycle tells the agent which intents make sense; the carried OpenRTB members have to match that story.

Reusing one JSON blob across hops is how both show up in production. A team logs the full auction state, copies the object into the next ARTF fixture, and forgets to drop `bid_response` when the lifecycle moves back to publisher stage. gRPC still accepts the bytes.

ARTF `tmax` is milliseconds budgeted for the mutation RPC inside the auction, not the OpenRTB bid timeout copied from `bid_request.tmax`. Reference samples use roughly 120 to 150 ms. Values above 1000 ms trigger [`artf.tmax.implausible`](https://rtblint.org/docs/rule-reference/artf-tmax-implausible/): the extension point runs inside an exchange timeout, and a budget measured in seconds usually means someone pasted an auction limit without converting units.

That warning does not fail the envelope by itself. It pairs badly with a mislabeled lifecycle: you can burn seconds of agent time on a call that still carries the wrong stage label and a ghost `bid_response`.

I maintain [RTBlint](https://rtblint.org), an open source OpenRTB and ARTF linter. Envelope checks run before mutation checks because lifecycle and intents define what the response is allowed to propose.

``` bash
$ rtblint validate --type artf-request rtb-request.json
FAILED (OpenRTB 2.6-202606 ARTF request envelope): 0 error(s), 1 warning(s).
- [warning] bid_response: lifecycle is LIFECYCLE_PUBLISHER_BID_REQUEST, which runs
  before any DSP has answered, yet the envelope carries a bid_response.
  (artf.lifecycle.payload_unexpected)
```

If the document never parses, nothing downstream runs. Truncated fixtures and log line limits show up as [`artf.payload.invalid_json`](https://rtblint.org/docs/rule-reference/artf-payload-invalid_json/) before lifecycle logic executes.

Pass two on responses pairs each mutation against `applicable_intents` and semantic paths in the payloads actually carried. Pass three applies accepted mutations and revalidates OpenRTB so field-level damage appears on the request the exchange will see.

The same rules run in the [ARTF simulator](https://rtblint.org/demo/artf/), MCP tools, and gRPC on `openadtech.rtblint.v1`. ARTF already mandates gRPC for the extension point; validating on that channel beats discovering stage skew only after deals activate against the wrong document.

[ARTF explained](https://rtblint.org/guides/artf-explained/) walks the request and response members without assuming you read the PDF first. The [docs index](https://rtblint.org/docs/) links every ARTF rule id, including lifecycle, tmax, and mutation path checks, if you want stable ids in CI.

RTBlint is independent of IAB Tech Lab. The rule ids above come from the public ARTF proto and the v1.0 document; they exist because lifecycle and payloads are contracts you can violate while the RPC still returns OK.
