Skip to content

compliance: remove Meta-shape payload_must_contain over-fit; extend identifier_paths echo across related steps in 4 storyboards #3969

@bokelley

Description

@bokelley

Two coupled findings from the three-expert review of #3962. Both touch the new `upstream_traffic` adoption.

A. Meta-shape over-fit in `payload_must_contain`

`sales-social/sync_audiences` and `audience-sync/create_audience` declare:

```yaml
payload_must_contain:

  • path: "users[*].hashed_email"
    match: present
    ```

That path assumes the upstream POST body has a top-level `users[]` with `hashed_email` per user — Google Customer Match / Meta CAPI nesting. Won't match TikTok (`data.audience.members[].email_hash`), Snap (`payload.data.list[].hash`), Pinterest (`audience.users[].HASHED_EMAIL`), or any non-Google/Meta shape. Storyboard fails for adopters whose upstream isn't Meta-shaped.

Fix: drop the `payload_must_contain` block on these two storyboards entirely. `identifier_paths` already does the value-echo verification across upstream shapes (it asserts the storyboard-supplied identifier value appears in the recorded payload at any depth — shape-agnostic). The path-shape assertion adds nothing the value-echo doesn't already cover, and over-constrains adopters whose upstream isn't Meta.

Storyboards in `adcontextprotocol/adcp`:

  • `static/compliance/source/specialisms/sales-social/index.yaml` (sync_audiences step)
  • `static/compliance/source/specialisms/audience-sync/index.yaml` (create_audience step)

B. Extend identifier-echo across related steps to the other 4 storyboards

`sales-social` is the only storyboard that uses the cross-step pattern: `sync_audiences` adds `hashed_email` in `add[]`, then `log_event` references the same `hashed_email` in `user_match`. The runner verifies both steps echo the same identifier upstream — the strongest anti-façade signal because a façade can't satisfy it by emitting some POST; it has to round-trip the buyer's specific identifier across two related calls.

The other 4 storyboards adopting `upstream_traffic` only assert single-step `min_count` or single-step `identifier_paths`. The pattern generalizes:

  • signal-marketplace: `search_by_spec` returns `signal_id` → `activate_on_platform` should reference the same `signal_id` upstream.
  • sales-non-guaranteed: `create_media_buy` returns `media_buy_id` → delivery / pacing steps should reference it upstream.
  • creative-ad-server: `build_creative` returns `creative_id` → delivery / impression steps should reference it upstream.
  • audience-sync has `discover` then `create` steps where similar echo could apply.

Each adoption is a small storyboard edit:

  1. Identify the cross-step identifier (signal_id, media_buy_id, creative_id, etc.).
  2. Add `identifier_paths` to the downstream step's `upstream_traffic` validation referencing the captured identifier.
  3. Optionally add `since: <prior_step_id>` so the assertion window scopes to traffic caused after the prior capture.

Why bundle these

Both are about the same surface (the 5 storyboards that adopted `upstream_traffic` in #3962) and both improve the anti-façade signal — A removes false-positive shape constraints, B adds true-positive echo verification. Single PR.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingclaude-triagedIssue has been triaged by the Claude Code triage routine. Remove to re-triage.compliance-suite

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions