DEV Community

Aleksander Sekowski
Aleksander Sekowski

Posted on

ARTF ADD_METRICS Can Propose a Metric With No Type. OpenRTB Requires Metric.type.

A publisher-side ARTF agent returns ADD_METRICS on /imp/imp-1. The payload carries one metric object with value: 0.82 and no type. The gRPC call completes. The orchestrator applies the patch. The bid request forwards to three DSPs.

Two of them no-bid. The third bids, but its viewability vendor cannot classify the metric because OpenRTB's Metric object requires type to say what the number means. The auction did not fail loudly. The agent handshake succeeded.

What Metric.type is for

OpenRTB attaches metrics at the impression, site, app, content, or deal level. Each entry is a Metric object with at least:

  • type: a free-form string naming the metric (for example viewability, click_through_rate, video_completion_rate)
  • value: a float
  • optional vendor when the number comes from a named measurement provider

The spec does not define a closed enum for type. That is intentional: buyers and sellers negotiate which strings they recognize. What the spec does require is that the field exist so the receiver knows which contract the float belongs to.

ARTF's ADD_METRICS intent maps onto that object. The agent proposes one or more metrics at a semantic path such as /imp/imp-1. The orchestrator merges them into the live bid request before the exchange forwards it.

The framework validates the RPC envelope, not the OpenRTB document after merge. A mutation can be "independently acceptable" in ARTF terms while producing a bid request that violates OpenRTB field requirements.

The mutation that parses but does not mean anything

Protobuf JSON for an ADD_METRICS response might look like this:

{
  "id": "extension-point-001",
  "mutations": [
    {
      "intent": "ADD_METRICS",
      "op": "OPERATION_ADD",
      "path": "/imp/imp-1",
      "metrics": {
        "metric": [
          { "value": 0.82, "vendor": "EXAMPLE" }
        ]
      }
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Nothing here violates ARTF's mutation schema. The intent matches the payload oneof. The path names an impression that exists. The value is a number.

What is missing is the only field that tells a buyer whether 0.82 is a viewability score, a completion rate, or something the agent invented on the spot.

I maintain RTBlint, an open source OpenRTB and ARTF linter. On the mutation pass it reports artf.mutation.metric_type_missing:

$ rtblint validate --type artf-response --request rtb-request.json rtb-response.json
FAILED (OpenRTB 2.6-202606 ARTF mutation set): 1 error(s), 0 warning(s).
- [error] mutations[0].metrics.metric[0].type: OpenRTB requires Metric.type;
  a metric without one cannot be interpreted by whoever receives the
  mutated request. (artf.mutation.metric_type_missing)
Enter fullscreen mode Exit fullscreen mode

Run the same files with --apply and the finding survives into the OpenRTB layer as a type mismatch on the merged document. The agent broke the auction object; the envelope was fine.

Encoding drift makes the same bug harder to see

ARTF carries OpenRTB inside a protobuf envelope. The IAB protobuf schema and the PDF spec disagree on how flag fields encode (secure: 1 versus secure: true). That split is a different failure mode, but it shares the same symptom: the transport accepts the bytes while the semantic consumer does not.

The OpenRTB two JSON dialects write-up walks the 28 bool-or-integer fields. ARTF hosts already speak protobuf JSON on the wire, so an agent that serializes metrics correctly but omits type is not confused by dialect; it is confused about which OpenRTB members are required after the patch lands.

Agents built from the v1.0 PDF examples have a second encoding layer to watch. Document-style mutations wrap payloads in value and spell intents in camelCase. RTBlint maps that vocabulary and warns with artf.mutation.legacy_spec_encoding because the reference server speaks the .proto, not the PDF. A metric missing type is orthogonal to that warning, but teams debugging "the RPC succeeded" often hit both at once.

Where to run the check

Validate in three passes when you host agents:

  1. Envelope. Lifecycle, applicable_intents, originator, and the carried bid request as protobuf JSON.
  2. Mutations. Intent, operation, path resolution, and intent-specific payload rules (including metric type).
  3. Applied. Merge accepted mutations and revalidate OpenRTB so you report what the agent introduced, not what arrived broken from upstream.
$ 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
Enter fullscreen mode Exit fullscreen mode

The same rules run in the ARTF simulator, as MCP tools (validate_artf_request, validate_artf_response with apply), and over gRPC on openadtech.rtblint.v1. ARTF already mandates gRPC for the extension point; putting the guardrail on that channel beats shelling out after the auction clock has moved on.

When a mutation fails for the wrong reason, artf.field.type_mismatch covers ARTF envelope members whose JSON type does not match the proto (for example a string where an enum is required). Metric type missing is narrower: the field is absent, not mistyped.

What to read next

The eight ARTF intents and which OpenRTB paths each one touches are summarized in ARTF explained. For checkpoint validation after every mutating stage, not only at the SSP edge, pair that guide with mutation-level rule references above.

RTBlint is independent of IAB Tech Lab. The rule ids come from the public ARTF proto and OpenRTB dated snapshots; they exist because ADD_METRICS is a contract on the merged bid request, not a promise that the gRPC status code tells you the auction is still valid.

Top comments (0)