Skip to content

feat(schemas): declare cta_values on image_carousel for the per-card cta - #8976

Open
KonstantinMirin wants to merge 1 commit into
adcontextprotocol:mainfrom
KonstantinMirin:schemas/image-carousel-cta-values
Open

KonstantinMirin wants to merge 1 commit into
adcontextprotocol:mainfrom
KonstantinMirin:schemas/image-carousel-cta-values

Conversation

@KonstantinMirin

Copy link
Copy Markdown
Collaborator

Closes #8960

What changes

image_carousel gains an optional cta_values parameter, the same type as cta_values on native_in_feed and image. core/assets/card-asset.json already says a card's cta MUST be one of the parent format's cta_values, but image_carousel did not declare it, so a carousel option could only carry it as an undeclared extra parameter on the open params object.

"params": {
  "card_aspect_ratio": "1:1",
  "cta_values": ["SHOP_NOW", "LEARN_MORE"]
}
  • When declared, every card's cta MUST be one of the listed values. A seller refuses any other value with CREATIVE_VALUE_NOT_ALLOWED, with error.field on that card's cta (for example creatives[0].assets.cards[2].cta on sync_creatives).
  • A card may still omit cta. The parameter closes the set; it does not make the field required.
  • When absent, a card's cta takes free text, and a seller does not refuse it as CREATIVE_VALUE_NOT_ALLOWED.

It is one optional property on an open params object, so it is a minor, like card_image_sizes in #8937. It carries x-added-in: "3.3.0".

Files

  • static/schemas/source/formats/canonical/image_carousel.json: the new property, with the description from the issue plus the sentence that a card may omit cta.
  • docs/creative/channels/carousels.mdx: the declaration example declares cta_values, the manifest example gives each card a cta from that set, and a new "Per-card CTA" section states the three rules above.
  • docs/reference/whats-new-in-3-3.mdx: a short entry after the card_image_sizes one.
  • static/examples/products/canonical/meta_carousel.json: declares cta_values: ["SHOP_NOW", "LEARN_MORE", "SIGN_UP"].
  • tests/canonical-format-conventions.test.cjs: the slot-param lint warned when cta_values was declared without a cta slot. image_carousel has no cta slot, since its cta_values governs each card in the cards slot, so the lint now checks cards for that canonical. Without this, the Meta carousel example warns.
  • tests/canonical-negative-fixtures.test.cjs: a positive control (a list of strings) and two cases that each break it in one way (a bare string, a non-string item).
  • tests/x-added-in-3-3-sweep.test.cjs: registers the new 3.3 property.
  • .changeset/image-carousel-cta-values.md: minor.

How this relates to #8949

#8949 writes Brian's answers on #8628 into the schemas and docs, including that CREATIVE_VALUE_NOT_ALLOWED covers a card's per-card cta with error.field on the card. This PR adds the declaration that rule points at. The two don't depend on each other and can merge in either order:

No storyboard step in this PR

The issue suggests a step like native_in_feed's reject_cta_not_in_enum. It is not in this PR. No agent in this repo checks a per-card cta: the training agent's closed-set check runs only on native_in_feed declarations, so a carousel step would fail against it until a carousel validator is added there. That validator and the step (a carousel option declaring cta_values, an accepted creative whose cards all use declared values, and the same creative with one card's cta outside the set) can follow as their own PR. The negative fixtures here cover the schema side: the two rejected cases pass validation against main's image_carousel.json and fail against this one.

Verification

  • npm run build:schemas
  • npm run test:schemas: pass
  • npm run test:additive-minor: pass (source vs 3.2.10, 0 new non-additive changes)
  • npm run test:canonical-negative: 91/91. Against main's image_carousel.json, the two new rejected cases fail ("got true, want false"); the positive control passes on both.
  • npm run test:canonical-conventions: clean. With main's lint, the updated Meta carousel example warns "declares cta_values but effective slots[] has no 'cta' slot".
  • npm run test:canonical-fixtures, canonical-manifest-constructibility, x-added-in-3-3-sweep: pass
  • npm run test:mcp-schema-projection: 41/41
  • Every test:storyboard-* lint (23), test:docs-nav, test:owned-links, test:schema-links, docs:json-field-audit: pass
  • json-schema-validation --file and snippet-validation --file on the changed doc pages: pass (no $schema-tagged or testable blocks)
  • check-changeset-protocol-scope.cjs and changeset status: pass (minor)
  • The repo pre-commit hook (.husky/pre-commit: image check, test:unit, the dynamic-import, format-identity and callApi checks, typecheck): pass

core/assets/card-asset.json makes a card's cta a closed set when the
parent format declares cta_values, but image_carousel did not declare
it, so a carousel option could only carry it as an undeclared extra
parameter on the open params object.

Add an optional cta_values list to image_carousel, the same type as on
native_in_feed and image, with x-added-in 3.3.0. When declared, every
card's cta must be one of the listed values and a seller refuses any
other value with CREATIVE_VALUE_NOT_ALLOWED, with error.field on that
card's cta. A card may still omit cta. When absent, a card's cta takes
free text.

Show the parameter in the carousel docs and the 3.3 notes, declare it
on the Meta carousel example, and teach the slot-param lint that on
image_carousel cta_values governs the cards slot. Negative fixtures
check the type: they fail against the schema without the property.

Closes adcontextprotocol#8960
@mintlify

mintlify Bot commented Nov 13, 2026

Copy link
Copy Markdown

Preview approval required

This pull request comes from a fork, so Mintlify won't build a preview until someone with write access approves commit 26e1181.

Approve preview

@aao-secretariat aao-secretariat Bot added the ladon/needs-human-review Ladon has escalated this PR for human review. label Nov 13, 2026

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ladon verdict: Escalate to human review

Escalate — gated path requires human/CODEOWNERS approval.

This PR modifies static/schemas/source/formats/canonical/image_carousel.json, which falls under the hard approval gate (static/schemas/source/**). gated_paths is true and review_decision is REVIEW_REQUIRED (not APPROVED), so decision-table row 2 fires: the gate is not satisfied and the outcome must be escalate.

The change itself is clean on the merits: image_carousel gains an optional cta_values (array of string) typed identically to the same field on native_in_feed and image, carrying x-added-in: 3.3.0. Schema↔docs coherence holds across carousels.mdx and whats-new-in-3-3.mdx, the minor changeset is correct for an additive Normative change, no oneOf/released-artifact concerns, and the tests (negative fixtures, x-added-in sweep, slot mapping to the existing cards slot) are consistent. The reviewer surfaced no Critical/High/Medium findings.

However, a clean diff does not lift the gate — only a real APPROVED review status does. A human/CODEOWNERS approval on the schema source file is required before this can merge.

Escalation reasons

  • Touches gated path static/schemas/source/formats/canonical/image_carousel.json and review_decision is REVIEW_REQUIRED — human/CODEOWNERS approval required.

Why human review

  • Modifies gated path static/schemas/source/formats/canonical/image_carousel.json (matches static/schemas/source/**) while review_decision is REVIEW_REQUIRED — human/CODEOWNERS approval required before merge.
  • This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/formats/canonical/image_carousel.json (modified) matches static/schemas/source/**) and the current GitHub review decision is 'REVIEW_REQUIRED', not APPROVED. This is a hard gate enforced in code — Ladon cannot auto-approve until a human/CODEOWNERS approval is recorded, regardless of how clean the diff is.

@aao-secretariat
aao-secretariat Bot requested a review from bokelley November 13, 2026 15:39

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ladon/needs-human-review Ladon has escalated this PR for human review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

image_carousel: declare cta_values for the per-card cta

1 participant