Conversation
… mutating-tool requests (#1604) Fixture-aware enrichers in `request-builder.ts` rebuilt their request body from scratch and only copied an enumerated set of fields from `step.sample_request` (start_time, end_time, packages for create_media_buy). Anything else the storyboard authored at the top level — `total_budget`, `buyer_ref`, `currency`, `reporting_webhook`, scenario-specific extensions — was silently dropped before the request hit the wire. The non-proposal `create_media_buy` path was the immediate trigger; PR #1603's proposal-mode branch already spread the fixture but the structural fix wasn't applied to the rest of the enricher. The fix spreads `sample_request` first (after `$context` injection), then layers the runner's substitutions (account, brand, normalised dates, packages with discovery-derived identifiers) on top. Envelope fields (`context`, `ext`, `push_notification_config`, `idempotency_key`) are deliberately omitted from the local spread and re-applied by the outer `enrichRequest` with `runnerVars` so mustache substitutions like `{{runner.webhook_url:<step_id>}}` expand correctly. The same `omitEnvelopeFields` discipline is now applied uniformly across `create_media_buy`, `update_media_buy`, `get_media_buys`, `get_media_buy_delivery`, and `comply_test_controller`. Audit of FIXTURE_AWARE_ENRICHERS (the only path where the bug manifests because they bypass the outer fixture overlay): - `create_media_buy` non-proposal — fixed (build-from-scratch dropped fields) - `create_media_buy` proposal — already spread, hardened with envelope omission so push_notification_config tokens expand correctly - `update_media_buy` — already spread; hardened with envelope omission - `get_media_buys` — already spread; hardened with envelope omission - `get_media_buy_delivery` — already spread; hardened with envelope omission - `comply_test_controller` — already spread; hardened with envelope omission Non-FIXTURE_AWARE enrichers don't manifest the bug because the outer `enrichRequest` already does `{ ...enriched, ...fixture }` so the fixture overlays the enricher's hardcoded keys. Regression test pinning the field-pass-through is added to `test/lib/request-builder.test.js` (verified to fail when the fix is reverted). The proposal-mode adapter gate's EXPECTED_FAILURES allowlist remains empty. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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
Issue #1604 —
src/lib/testing/storyboard/request-builder.tsfixture-aware enrichers rebuilt their request body from scratch and silently dropped any top-levelsample_requestfield outside an enumerated allowlist. The non-proposalcreate_media_buypath was the immediate trigger (proposal-mode storyboards loseproposal_id,total_budget,idempotency_keyfrom the YAML before they reach the wire). PR #1603 patched the proposal-mode branch but didn't apply the structural fix to the rest of the enricher.Audit
FIXTURE_AWARE_ENRICHERSis the only set where the bug manifests — these enrichers bypass the outer fixture overlay ({ ...enriched, ...fixture }) inenrichRequest. Non-fixture-aware enrichers don't drop fields because the outer merge re-applies the fixture.create_media_buy(non-proposal)sample_requestthen overridecreate_media_buy(proposal)update_media_buyget_media_buysget_media_buy_deliverycomply_test_controllerStructural fix
Spread
sample_requestfirst (after$contextinjection), then layer the runner's substitutions (account, brand, normalised dates, packages with discovery-derived identifiers) on top. Envelope fields (context,ext,push_notification_config,idempotency_key) are deliberately omitted from the local spread and re-applied by the outerenrichRequestwithrunnerVarsso mustache substitutions like{{runner.webhook_url:<step_id>}}expand correctly.A new
omitEnvelopeFieldshelper centralises the envelope-omission discipline and is applied uniformly across every fixture-aware enricher that spreads sample_request.Regression test
test/lib/request-builder.test.js— new testpreserves top-level sample_request fields the enricher does not normalise (#1604). Pinstotal_budget,buyer_ref,currency,reporting_webhookpass-through. Verified to fail when the fix is reverted (79/80 pass; the new test fails as expected).Allowlist
test/examples/hello-seller-adapter-proposal-mode.test.jsEXPECTED_FAILURESis already[](cleared by PR #1603 ahead of this structural fix). No further change required.Verification
npm run format:check— cleannpx tsc --noEmit— cleannode --test test/examples/hello-seller-adapter-proposal-mode.test.js— 3/3 passnode --test test/lib/request-builder.test.js test/lib/storyboard-envelope-passthrough.test.js— 84/84 passnpm test— 8338 pass, 0 fail (3 skipped)Refs
Test plan
🤖 Generated with Claude Code