feat(conformance): add omit_account escape hatch to StoryboardStep (#1696)#1700
Merged
Merged
Conversation
…1696) Follow-up to PR #1683 which removed the account_from_brand shim. Storyboard schema_validation steps that deliberately test seller-side missing-account rejection can no longer reach the seller because the SDK's client-side ValidationError short-circuits before the wire call. Mirrors the existing omit_idempotency_key pattern: a step-level boolean that suppresses account injection in applyBrandInvariant (both synthetic-construction and natural-key-merge branches) and the normalizeRequestParams/validateRequest account-required checks (via skipAccountValidation on TaskOptions). For non-A2A runs, also triggers the raw-probe defense-in-depth path. https://claude.ai/code/session_01AW5JtCv7bVCVj17PHspMY8
…pe hatch - Clarify in SingleAgentClient comments that skipAccountValidation bypasses the entire Zod schema parse (matching skipIdempotencyAutoInject behavior), not just the account field — both sites updated - Add loader co-requirement: omit_account: true now requires expect_error: true (loader throws at parse time; accountless create_media_buy always fails) - Extend omit_account JSDoc with: no-op note for non-create_media_buy tasks, request-builder caveat for future update_media_buy use, expect_error pairing rule - Add ordering-anchor comment in runner.ts noting testsMissingAccount must remain after applyBrandInvariant call https://claude.ai/code/session_01AW5JtCv7bVCVj17PHspMY8
Auto-generated by build:lib (timestamp only change); package-lock refreshed by npm install run during CI setup. https://claude.ai/code/session_01AW5JtCv7bVCVj17PHspMY8
Two reviewer-flagged gaps:
1. `test/lib/storyboard-account-invariant.test.js` gains a loader test
asserting `omit_account: true` without `expect_error: true` throws at
parse time (was previously enforced in code but uncovered by tests).
2. `test/request-normalizer-package-params.test.js` adds `account: {
account_id: 'test-acc' }` to both fixtures. After #1683 landed the
account-required throw runs before normalizePackageParams, so the
package-shape gates (#1681) need an account in the fixture to be the
gate under test.
bokelley
added a commit
that referenced
this pull request
May 11, 2026
bokelley
added a commit
that referenced
this pull request
May 11, 2026
…applicable in ComplianceResult (#1701) * feat(conform): split storyboards_missing_tools from storyboards_not_applicable (#1695) Adds ComplianceResult.storyboards_missing_tools to distinguish storyboards filtered because the agent declared the protocol but a required tool was absent from storyboards_not_applicable (version-gated, protocol not declared). Also fixes pre-existing duplicate ValidationError import in request-normalizer.ts. Closes #1695 https://claude.ai/code/session_01J4JR1oK6rvbGZstZxZL4yG * feat(conform): update complyImpl to route required_tools stubs to storyboards_missing_tools Split the notApplicable array into two: version-gated entries remain in notApplicable (→ storyboards_not_applicable) and required_tools-filtered entries go to missingToolStoryboards (→ storyboards_missing_tools). Part of #1695 https://claude.ai/code/session_01J4JR1oK6rvbGZstZxZL4yG * fix(comply): restore escape sequences in sanitizeAgentText and separator widths Revert two incidental prettier-formatting changes that crept in during the previous commit: 1. sanitizeAgentText regex: prettier had converted explicit Unicode escape sequences ( --) into embedded literal bidi control characters. Reverted to escape sequences — the function strips these characters and having them appear as invisible literals in the source makes security review much harder. 2. Section separator comments: prettier trimmed the ─────── bars from 60 to 56 characters. Restored original width to preserve existing style. * fix(comply): restore escape sequences in sanitizeAgentText and separator widths Revert two incidental prettier-formatting changes from the previous commit: 1. sanitizeAgentText regex: prettier had converted explicit Unicode escape sequences ( --) into embedded literal bidi control characters. Reverted to named escape sequences — the function strips these chars; having them embedded invisibly in security-sensitive source makes code review much harder. 2. Section separator comments: prettier trimmed the ─── bars from 60 to 56 characters. Restored original width. * test: encoding verification * fix(comply): restore \uXXXX escape sequences in sanitizeAgentText regex Revert incidental prettier change that converted Unicode escape sequences to embedded literal bidi control characters in the sanitizeAgentText regex. The function strips these characters; having them appear as invisible literals in security-sensitive source makes code review much harder. Also restores the section separator comments from 56 to 60 dashes (also prettified in the same pass). * chore: remove accidental test artifact * fix(conform): bump changeset to major, document skip_causes for tool names * fix(test): pass account in pre-3.0 package shape tests Same fix as on #1698/#1699/#1700 — after #1683 landed, create_media_buy requires account. Add `account: { account_id: 'test-acc' }` to both fixtures so the package-shape gates (#1681) remain the gate under test.
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.
Closes #1696
Summary
omit_account?: booleantoStoryboardStep(mirrorsomit_idempotency_keypattern) so schema_validation storyboard steps can exercise seller-side missing-account rejection oncreate_media_buywithout being short-circuited by client-side validation.applyBrandInvariantskips both the synthetic-construction and natural-key-merge branches; (2)normalizeRequestParamsskips theaccount-required throw viaskipAccountValidation; (3) raw-probe defense-in-depth routes non-A2A steps through raw HTTP so no SDK normalization layer can silently re-injectaccount.omit_account: truenow requiresexpect_error: true— the loader throws at parse time with a clear message so storyboard authors catch the error at load, not run time.skipAccountValidationis active (matching pre-existingskipIdempotencyAutoInjectbehavior); comments at bothSingleAgentClientguard sites now make this explicit.omit_accountclarifies: no-op on non-create_media_buytasks,request-builder.tscaveat for future tasks, andexpect_errorpairing requirement.Context
PR #1683 removed the
account_from_brandfabrication shim socreate_media_buycalls withoutaccountnow throwValidationErrorclient-side before the wire call. This means storyboard steps that deliberately test a seller's missing-account rejection path (schema_validationcategory) can no longer reach the seller — the client throws first and the grader never sees the server's response.omit_account: trueis the minimal escape hatch to restore that path, exactly mirroring howomit_idempotency_key: truehandles the analogous idempotency-key test vector.What was tested
test/lib/storyboard-account-invariant.test.js(all pass):applyBrandInvariant— synthetic-construction branch, natural-key-merge branch, normal path, mutation guard, false defaultrunStoryboard— missing account reaches mock server, normal step auto-injects account, bearer-auth raw-probe forwards token without injecting accountnpm run typecheck— cleannpm run build:lib— cleanPre-PR review
Code-reviewer (iteration 1): ✅ no blockers. Two issues addressed:
SingleAgentClientcomments thatskipAccountValidationbypasses the entire Zod schema parse (not just the account field) — consistent with pre-existingskipIdempotencyAutoInjectbehavior; both@internalflags.runner.tsnotingtestsMissingAccountmust remain after theapplyBrandInvariantcall.Ad-tech protocol expert (iteration 1): ✅ verdict: sound-with-caveats. One blocker addressed:
request-builder.tsauto-injectsaccountforupdate_media_buyandget_media_buys/get_media_buy_deliveryandomit_accountdoes not suppress that. Added a@seewarning in the JSDoc so future storyboard authors know the flag only coverscreate_media_buytoday. Added loader co-requirement validation (omit_account: truerequiresexpect_error: true) per the expert's nit.https://claude.ai/code/session_01AW5JtCv7bVCVj17PHspMY8
Generated by Claude Code