Skip to content

feat(conformance): add omit_account escape hatch to StoryboardStep (#1696)#1700

Merged
bokelley merged 9 commits into
mainfrom
claude/issue-1696-omit-account-escape-hatch
May 11, 2026
Merged

feat(conformance): add omit_account escape hatch to StoryboardStep (#1696)#1700
bokelley merged 9 commits into
mainfrom
claude/issue-1696-omit-account-escape-hatch

Conversation

@bokelley
Copy link
Copy Markdown
Contributor

Closes #1696

Summary

  • Add omit_account?: boolean to StoryboardStep (mirrors omit_idempotency_key pattern) so schema_validation storyboard steps can exercise seller-side missing-account rejection on create_media_buy without being short-circuited by client-side validation.
  • Three-layer suppression: (1) applyBrandInvariant skips both the synthetic-construction and natural-key-merge branches; (2) normalizeRequestParams skips the account-required throw via skipAccountValidation; (3) raw-probe defense-in-depth routes non-A2A steps through raw HTTP so no SDK normalization layer can silently re-inject account.
  • Loader co-requirement: omit_account: true now requires expect_error: true — the loader throws at parse time with a clear message so storyboard authors catch the error at load, not run time.
  • All Zod schema validation is suppressed when skipAccountValidation is active (matching pre-existing skipIdempotencyAutoInject behavior); comments at both SingleAgentClient guard sites now make this explicit.
  • JSDoc on omit_account clarifies: no-op on non-create_media_buy tasks, request-builder.ts caveat for future tasks, and expect_error pairing requirement.

Context

PR #1683 removed the account_from_brand fabrication shim so create_media_buy calls without account now throw ValidationError client-side before the wire call. This means storyboard steps that deliberately test a seller's missing-account rejection path (schema_validation category) can no longer reach the seller — the client throws first and the grader never sees the server's response.

omit_account: true is the minimal escape hatch to restore that path, exactly mirroring how omit_idempotency_key: true handles the analogous idempotency-key test vector.

What was tested

  • 8 new tests in test/lib/storyboard-account-invariant.test.js (all pass):
    • 5 unit tests for applyBrandInvariant — synthetic-construction branch, natural-key-merge branch, normal path, mutation guard, false default
    • 3 wire-level integration tests for runStoryboard — missing account reaches mock server, normal step auto-injects account, bearer-auth raw-probe forwards token without injecting account
  • npm run typecheck — clean
  • npm run build:lib — clean

Pre-PR review

Code-reviewer (iteration 1): ✅ no blockers. Two issues addressed:

  • Clarified in SingleAgentClient comments that skipAccountValidation bypasses the entire Zod schema parse (not just the account field) — consistent with pre-existing skipIdempotencyAutoInject behavior; both @internal flags.
  • Added ordering-anchor comment in runner.ts noting testsMissingAccount must remain after the applyBrandInvariant call.
  • Updated JSDoc to note "Setting it on any other task has no effect and is ignored."

Ad-tech protocol expert (iteration 1): ✅ verdict: sound-with-caveats. One blocker addressed:

  • request-builder.ts auto-injects account for update_media_buy and get_media_buys/get_media_buy_delivery and omit_account does not suppress that. Added a @see warning in the JSDoc so future storyboard authors know the flag only covers create_media_buy today. Added loader co-requirement validation (omit_account: true requires expect_error: true) per the expert's nit.

Triage-managed PR — opened by the automated triage agent in response to issue #1696 (author: @bokelley, labels: enhancement, conformance, library). Human review required before merge.

https://claude.ai/code/session_01AW5JtCv7bVCVj17PHspMY8


Generated by Claude Code

claude added 4 commits May 11, 2026 17:26
…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
claude and others added 2 commits May 11, 2026 17:50
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
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.
@bokelley bokelley marked this pull request as ready for review May 11, 2026 18:22
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.
@bokelley bokelley merged commit 8258e1c into main May 11, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add omit_account escape hatch for schema_validation storyboards

2 participants