fix(testing): storyboard request-builders emit spec shapes for log_event + create_media_buy (#793)#794
Merged
Merged
Conversation
…ent + create_media_buy (#793) `log_event` now honors `step.sample_request` and uses spec field names (`event_time` + `custom_data.{value,currency}`) in the synthetic fallback. `create_media_buy` emits every authored package instead of dropping `packages[1+]`; the first package keeps context-override for discovery-derived identifiers, additional packages pass through with context injection only. Framework-dispatch agents running zod at the MCP boundary previously rejected these with -32602 invalid_type; legacy-dispatch let them through. Surfaced while diagnosing adcontextprotocol/adcp#2872.
This was referenced Apr 22, 2026
bokelley
added a commit
that referenced
this pull request
Apr 22, 2026
…803) (#807) * test(testing): schema round-trip invariant for every request builder (#803) Iterate every task in `TOOL_REQUEST_SCHEMAS` (plus the two brand-rights schemas that ship outside the MCP tool surface) with a matching storyboard request builder, build its fallback request, and assert it parses cleanly against the generated Zod schema. Catches the #789 / #792 / #793 / #794 class of drift before it ships — any builder that emits off-spec field names or types now fails CI. Also fixes eight pre-existing fallbacks the invariant surfaced: - `update_media_buy.packages[0].package_id` defaulted - `update_rights` + `creative_approval` use spec `rights_id` (not `rights_grant_id`); `creative_approval` emits `creative_url` + `creative_id` - `sync_creatives` + `buildAssetsForFormat` emit the `asset_type` discriminator and spec-correct video fields - `calibrate_content` + `validate_content_delivery` artifact `assets` is an array of typed assets, not an object map - `activate_signal` defaults `destinations` to a placeholder agent entry - `create_content_standards` + `update_content_standards` align with the current `scope` + `policies` shape - `si_get_offering` + `si_initiate_session` pass `options.si_context` through `intent` (string) instead of `context` (ContextObject); `si_initiate_session` emits the required `intent` Closes #803. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(testing): address review - MUTATING_TASKS, enumerated coverage, si intent default Expert review feedback on PR #807: - Use exported `MUTATING_TASKS` from `src/lib/utils/idempotency.ts` instead of re-implementing Zod shape introspection in the test. Handles the two brand-rights tasks (creative_approval, update_rights) via a small EXTRA_MUTATING set — both are mutating per their generated schemas but intentionally live outside TOOL_REQUEST_SCHEMAS. - Replace ">= 30 covered" floor with an enumerated EXPECTED_COVERED_TASKS list. Adding a new builder/schema pair now forces a conscious list update rather than drifting past a magic number. - `si_initiate_session` intent default is now "Browse available offerings" (a real user-ask) instead of "E2E test session" (test metadata). Intent dispatches meaningfully on SI agents; storyboards override via sample_request for intent-specific paths. - Regenerate docs/llms.txt and docs/TYPE-SUMMARY.md (upstream compliance- cache update landed while this branch was open). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore: sync version.ts + package-lock.json to 5.11.0 `sync-version` regenerated `src/lib/version.ts` and the package-lock to match `package.json` (5.11.0). The branch's version.ts had been carried over from a 5.10.0-era rebase point. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced Apr 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #793 — two storyboard
REQUEST_BUILDERSinsrc/lib/testing/storyboard/request-builder.tsemit non-spec payloads. Framework-dispatch agents running zod at the MCP boundary reject them with-32602 invalid_type; legacy-dispatch permissively lets them through. Surfaced while diagnosing adcontextprotocol/adcp#2872.Bug A —
log_eventtimestamp(spec:event_time) andvalue: { amount, currency }(spec:custom_data.{value,currency}percore/event.json+core/event-custom-data.json).step.sample_request, so storyboards (sales_catalog_driven,sales_social) that author spec-conformant events withevent_time/content_ids/ siblings were silently discarded.Fix: honor
step.sample_requestfirst (same convention assync_catalogs,report_usage,update_media_buy,sync_creatives); correct the synthetic fallback's field names.Bug B —
create_media_buypackages: [pkg]regardless of how many packages the storyboard'ssample_requestauthored. Multi-package storyboards (sales_non_guaranteed) lostpackages[1+], leavingcontext_outputslikesecond_package_idunresolved — the next step (update_media_buyusing$context.second_package_id) was then skipped with "unresolved context variables from prior steps". Reproduced under both framework and legacy dispatch.Fix: emit every authored package. First package still receives context-derived
product_id/pricing_option_id(so single-package storyboards against arbitrary sellers keep working); additional packages pass through with context injection only, preserving per-packageproduct_id,bid_price,pricing_option_id, andcreative_assignments.Tests
Four new regression tests in
test/lib/request-builder.test.js:create_media_buyemits every package when sample_request authors multiple.create_media_buyinjects context into additional packages.log_eventfallback uses spec field names (event_time,custom_data).log_eventhonorsstep.sample_requestwith context injection.All 37 request-builder tests and 1396 storyboard-completeness tests pass.
Deeper structural issues (filing as follow-ups)
Expert review (code-reviewer + ad-tech-protocol-expert) flagged a broader structural issue and several additional spec-violating builders that are out of scope for this PR:
REQUEST_BUILDERSentries take precedence oversample_requestunless the builder explicitly opts in withif (step.sample_request) return injectContext(...)— a pattern that's now duplicated in ~12 builders. The correct default is "sample_request is authoritative; builder fills discovery-derived identifiers." Will file as a separate refactor.schemas/cache/latest/:si_get_offeringemitscontextas a string, butcore/context.jsonis an object ref.si_initiate_sessionstuffs the intent string intocontext; schema requiresintent+identitypersi-identity.json.sync_governanceemitscredentials: "test-governance-token"(21 chars) but schema requiresminLength: 32; also never honorsstep.sample_request.sync_event_sources,sync_audiences(narrow delegation),list_content_standards,sync_accounts— same "ignores sample_request" class as Bug A.Both experts also suggested a schema-driven invariant test that round-trips every builder's output through the generated Zod schema. Worth adding alongside the structural refactor.
Test plan
node --test test/lib/request-builder.test.js— 37 passnode --test test/lib/storyboard-completeness.test.js— 1396 passnpm run build— cleantsc --noEmit— clean🤖 Generated with Claude Code