Skip to content

Storyboards: shallow validation gap on read tasks + missing storyboards for 7 tasks #4291

Description

@bokelley

Problem

Current storyboard validations on read/list tasks are essentially schema + correlation_id echo. Across all field_value checks in static/compliance/source/specialisms/:

  • ~119/125 are path: \"context.correlation_id\" echoes
  • Only ~6 inspect actual response content (compliant, verdict, deployments[0].type, signal_id.source, success, deleted, status, brand_id)

A seller can return wrong, empty, or unrelated data and pass every read storyboard.

Examples of the gap

  • get_media_buys is exercised in 6 storyboards (sales-broadcast-tv, sales-guaranteed, sales-non-guaranteed, protocols/media-buy, get-media-buys-pagination-integrity, idempotency). None assert that media_buys[0].media_buy_id == \$context.media_buy_id from the prior create_media_buy. The seller can return any media buy.
  • get_creative_delivery (creative-ad-server) — schema + correlation_id only. No assertions on impressions, spend, variants, or media-buy linkage.
  • get_media_buy_delivery — same shallow pattern across 5 specialisms.
  • Lists (list_creatives, list_property_lists, list_collection_lists, list_content_standards, list_accounts, list_creative_formats) — schema + correlation_id; never asserts the just-created entity appears.

Two tracks

Track A — Data-grounded validations on existing read steps

Add cross-step assertions where state is already threaded through \$context.*:

  • get_media_buys / get_media_buy_delivery — assert returned media_buy_id matches the captured one
  • get_creative_delivery — assert returned creative_ids include the synced ones; impressions ≥ 0; spend ≤ buy budget
  • list_* after a create_* — assert the created id appears in the list response
  • validate_property_delivery is the existing reference pattern (asserts compliant: false based on input shape) — generalize that approach

Most of these need the cross-step comparison primitive in #2642 (field_equals_context, field_subset_of_context, etc.). Track A is partially blocked on that schema work.

In-step assertions that don't need new primitives (and can land now):

  • field_present on substantive fields, not just top-level keys (e.g., media_buys[0].packages[0].status, delivery.totals.impressions)
  • field_value for known-deterministic fields (e.g., when the prior step seeded a fixture, the read should return the seeded brand domain)

Track B — Missing storyboards for 7 tasks

These tasks exist in static/schemas/source/**/*-request.json but appear in zero storyboard steps:

Task Domain Notes
search_brands brand Brand discovery via natural language; no coverage
get_creative_features creative Semantic feature extraction; no coverage
get_media_buy_artifacts media-buy IO/PDF artifact retrieval; no coverage
update_rights brand Modify acquired rights; no coverage
creative_approval creative Review callback; no coverage
tasks_get core Async polling — no end-to-end working→submitted→completed storyboard
tasks_list core Same

identity_match / context_match (TMP) are intentionally out of scope here — separate track.

Cross-cutting gaps surfaced during the skim

  1. No state-roundtrip assertions — IDs threaded into \$context are never validated as the response payload (depends on Storyboard schema: cross-step comparison validation primitive #2642).
  2. No quantitative invariants — "spend ≤ budget", "impressions ≥ 0", "totals == sum of packages", "flight_dates within campaign window" are nowhere.
  3. No async polling storyboardtasks/get is only meaningful after a working/submitted response and there's no storyboard exercising it.
  4. Read-task error paths thin — governance-denied is well covered, but auth/not_found/validation errors on read tasks are largely absent.

Suggested sequencing

  1. Land Storyboard schema: cross-step comparison validation primitive #2642 (cross-step comparison primitive).
  2. Track A pass: add data-grounded validations to existing read steps using the new primitives.
  3. Track B: add storyboards for the 7 missing tasks (each as its own PR; tasks_get/tasks_list likely as one async-polling storyboard under protocols/).
  4. Quantitative invariants pass (separate, may need new check kinds for arithmetic).

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    claude-triagedIssue has been triaged by the Claude Code triage routine. Remove to re-triage.compliance-suiteenhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions