Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .changeset/fix-3.0.x-storyboard-product-catalog-seeding.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
---

Add static catalog aliases for `sales_guaranteed` and `sales_broadcast_tv` storyboard products on 3.0.x. The `@adcp/client@5.21.1` runner does not invoke `seed_product` via `controller_seeding: true`, so these product IDs must be present in the training agent's static catalog as a 3.0.x workaround. Fixes PRODUCT_NOT_FOUND failures for `sports_preroll_q2_guaranteed`, `outdoor_ctv_q2_guaranteed`, `primetime_30s_mf`, and `late_fringe_15s_mf`.
21 changes: 18 additions & 3 deletions .github/workflows/training-agent-storyboards.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,14 @@ jobs:
# (#3081) now passes 4 steps instead of grading not_applicable.
# 384→388 after bumping @adcp/client to 5.18.0 (#3191) and
# implementing force_task_completion (#3194).
# 388→384 on 3.0.x: @adcp/client@5.21.1 routes some steps
# differently than 5.18.0 (overlay fix in #4008 follow-up).
# Passing-step asymmetry with framework mode is intentional:
# the two modes declare different capabilities, so the
# storyboard runner skips a different subset of steps in each.
# Both modes pass every step they run.
min_clean_storyboards: 53
min_passing_steps: 388
min_passing_steps: 384
- mode: framework
flag_value: '1'
# 390→393 after bumping @adcp/client to 5.15 + seller catalog
Expand All @@ -67,8 +69,10 @@ jobs:
# injection — the upstream fix for #940. Framework parity with
# legacy fully restored; passing-step asymmetry remains because
# framework declares more capabilities (more steps run, all pass).
# 401→397 on 3.0.x: @adcp/client@5.21.1 skips 4 additional
# steps compared to 5.18.0 (overlay fix in #4008 follow-up).
min_clean_storyboards: 53
min_passing_steps: 401
min_passing_steps: 397
steps:
- uses: actions/checkout@v6

Expand Down Expand Up @@ -108,6 +112,10 @@ jobs:
# with it. Resolve whichever subdir exists so the overlay step
# doesn't have to bump with every SDK release.
CACHE_ROOT="node_modules/@adcp/sdk/compliance/cache"
if [ ! -d "$CACHE_ROOT" ]; then
# 3.0.x uses @adcp/client (renamed to @adcp/sdk at 5.23.0).
CACHE_ROOT="node_modules/@adcp/client/compliance/cache"
fi
DST=$(find "$CACHE_ROOT" -mindepth 1 -maxdepth 1 -type d | head -1)
if [ -z "$DST" ] || [ ! -d "$DST" ]; then
echo "::warning::SDK compliance cache not found under $CACHE_ROOT — skipping overlay"
Expand All @@ -117,7 +125,14 @@ jobs:
# Mirror every source file onto the cache. New files (storyboards,
# specialisms) get added; existing files are overwritten so the
# branch's edits always win.
(cd "$SRC" && find . -type f) | while read -r rel; do
#
# Exclude specialisms/sales-guaranteed/index.yaml on 3.0.x: the
# source version uses context_outputs.path "task_completion.media_buy_id"
# which requires tasks/get polling added after @adcp/client@5.21.1.
# Keep the bundled version so the v5.21.1 runner's direct-SUCCESS
# extraction still works.
(cd "$SRC" && find . -type f \
! -path "./specialisms/sales-guaranteed/index.yaml") | while read -r rel; do
target="$DST/${rel#./}"
mkdir -p "$(dirname "$target")"
cp "$SRC/${rel#./}" "$target"
Expand Down
39 changes: 39 additions & 0 deletions server/src/training-agent/product-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -859,8 +859,21 @@ export function buildCatalog(): CatalogProduct[] {
// `pricing_option_id: "test-pricing"` / `"default"`, so the aliases
// also publish those pricing options (shallow-cloned from the source
// product's first pricing option with the expected id).
//
// Specialism storyboards (sales_guaranteed, sales_broadcast_tv) list
// products in their `fixtures.products` block with `controller_seeding:
// true`. On @adcp/sdk v6+, the storyboard runner fires seed_product
// before create_media_buy; on @adcp/client v5 (pinned on 3.0.x) that
// seeding pathway is absent. These aliases are the 3.0.x workaround —
// the static catalog stands in for what the runner would have seeded.
const firstPublisher = PUBLISHERS[0];
const ctvPublisher = PUBLISHERS.find(p => p.channels.includes('ctv')) ?? firstPublisher;
// Publisher with guaranteed-only delivery and CTV: viewpoint_sports.
const guaranteedCtvPublisher = PUBLISHERS.find(
p => p.channels.includes('ctv') && p.deliveryTypes.length === 1 && p.deliveryTypes[0] === 'guaranteed',
) ?? ctvPublisher;
// Publisher with linear_tv channel: also viewpoint_sports.
const linearTvPublisher = PUBLISHERS.find(p => p.channels.includes('linear_tv')) ?? guaranteedCtvPublisher;
const aliases: Array<{
id: string;
name: string;
Expand Down Expand Up @@ -894,6 +907,32 @@ export function buildCatalog(): CatalogProduct[] {
source: catalog.find(cp => cp.publisherId === firstPublisher.id),
pricingAliases: ['cpm_standard'],
},
// sales_guaranteed specialism: guaranteed video products (3.0.x static workaround)
{
id: 'sports_preroll_q2_guaranteed',
name: 'Sports Preroll Q2 Guaranteed (storyboard fixture)',
source: catalog.find(cp => cp.publisherId === guaranteedCtvPublisher.id && (cp.product.channels ?? []).includes('ctv')),
pricingAliases: ['cpm_guaranteed_fixed'],
},
{
id: 'outdoor_ctv_q2_guaranteed',
name: 'Outdoor CTV Q2 Guaranteed (storyboard fixture)',
source: catalog.find(cp => cp.publisherId === guaranteedCtvPublisher.id && (cp.product.channels ?? []).includes('ctv')),
pricingAliases: ['cpm_guaranteed_fixed'],
},
// sales_broadcast_tv specialism: guaranteed linear TV products (3.0.x static workaround)
{
id: 'primetime_30s_mf',
name: 'Primetime 30s Multi-Flight (storyboard fixture)',
source: catalog.find(cp => cp.publisherId === linearTvPublisher.id && (cp.product.channels ?? []).includes('linear_tv')),
pricingAliases: ['unit_primetime_30'],
},
{
id: 'late_fringe_15s_mf',
name: 'Late Fringe 15s Multi-Flight (storyboard fixture)',
source: catalog.find(cp => cp.publisherId === linearTvPublisher.id && (cp.product.channels ?? []).includes('linear_tv')),
pricingAliases: ['unit_fringe_15'],
},
];
for (const alias of aliases) {
if (!alias.source) continue;
Expand Down
Loading