Repository navigation
feat(schemas): declare cta_values on image_carousel for the per-card cta - #8976
KonstantinMirin wants to merge 1 commit into
Conversation
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
Preview approval requiredThis pull request comes from a fork, so Mintlify won't build a preview until someone with write access approves commit |
There was a problem hiding this comment.
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.jsonandreview_decisionisREVIEW_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.
Closes #8960
What changes
image_carouselgains an optionalcta_valuesparameter, the same type ascta_valuesonnative_in_feedandimage.core/assets/card-asset.jsonalready says a card'sctaMUST be one of the parent format'scta_values, butimage_carouseldid not declare it, so a carousel option could only carry it as an undeclared extra parameter on the openparamsobject.ctaMUST be one of the listed values. A seller refuses any other value withCREATIVE_VALUE_NOT_ALLOWED, witherror.fieldon that card'scta(for examplecreatives[0].assets.cards[2].ctaonsync_creatives).cta. The parameter closes the set; it does not make the field required.ctatakes free text, and a seller does not refuse it asCREATIVE_VALUE_NOT_ALLOWED.It is one optional property on an open
paramsobject, so it is a minor, likecard_image_sizesin #8937. It carriesx-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 omitcta.docs/creative/channels/carousels.mdx: the declaration example declarescta_values, the manifest example gives each card actafrom 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 thecard_image_sizesone.static/examples/products/canonical/meta_carousel.json: declarescta_values: ["SHOP_NOW", "LEARN_MORE", "SIGN_UP"].tests/canonical-format-conventions.test.cjs: the slot-param lint warned whencta_valueswas declared without actaslot.image_carouselhas noctaslot, since itscta_valuesgoverns each card in thecardsslot, so the lint now checkscardsfor 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_ALLOWEDcovers a card's per-cardctawitherror.fieldon 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:image_carousel.json, docs(creative): clarify cta errors, carousel defaults, asset_types and product formats #8949 edits the top-level description,min_cards,max_cardsandallowed_card_media_asset_types; this PR addscta_valuesaftercard_description_max_chars. Incarousels.mdx, docs(creative): clarify cta errors, carousel defaults, asset_types and product formats #8949 adds a "Card media and card count" section before "Card image size"; this PR edits the two examples above it and adds "Per-card CTA" after it.git merge-treeof this branch with docs(creative): clarify cta errors, carousel defaults, asset_types and product formats #8949's head (d2d11ac) reports no conflicts.CREATIVE_VALUE_NOT_ALLOWEDtext andcore/assets/card-asset.jsonalone, because docs(creative): clarify cta errors, carousel defaults, asset_types and product formats #8949 rewrites both. The newcta_valuesdescription uses docs(creative): clarify cta errors, carousel defaults, asset_types and product formats #8949's wording (CREATIVE_VALUE_NOT_ALLOWED,error.fieldon the card'scta).card-asset.jsonctanameimage_carouselcta_valuesinstead of "the parent format". That is the sentence docs(creative): clarify cta errors, carousel defaults, asset_types and product formats #8949 rewrites, so I've left it for a one-line follow-up once docs(creative): clarify cta errors, carousel defaults, asset_types and product formats #8949 merges. Until then the sentence is already correct:image_carouselis the only canonical with acardsslot.tests/mcp-schema-projection.test.cjsis unchanged.cta_valuesreachescomply-test-controller-request.jsonthrough the seeded Product'sformat_optionsand adds 487 bytes (1_329_553 to 1_330_040 on currentmain). With docs(creative): clarify cta errors, carousel defaults, asset_types and product formats #8949's 890 bytes that comes to about 1_330_930, under the existing 1_388_000 bound.No storyboard step in this PR
The issue suggests a step like
native_in_feed'sreject_cta_not_in_enum. It is not in this PR. No agent in this repo checks a per-cardcta: the training agent's closed-set check runs only onnative_in_feeddeclarations, so a carousel step would fail against it until a carousel validator is added there. That validator and the step (a carousel option declaringcta_values, an accepted creative whose cards all use declared values, and the same creative with one card'sctaoutside the set) can follow as their own PR. The negative fixtures here cover the schema side: the two rejected cases pass validation againstmain'simage_carousel.jsonand fail against this one.Verification
npm run build:schemasnpm run test:schemas: passnpm run test:additive-minor: pass (source vs 3.2.10, 0 new non-additive changes)npm run test:canonical-negative: 91/91. Againstmain'simage_carousel.json, the two new rejected cases fail ("got true, want false"); the positive control passes on both.npm run test:canonical-conventions: clean. Withmain'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: passnpm run test:mcp-schema-projection: 41/41test:storyboard-*lint (23),test:docs-nav,test:owned-links,test:schema-links,docs:json-field-audit: passjson-schema-validation --fileandsnippet-validation --fileon the changed doc pages: pass (no$schema-tagged or testable blocks)check-changeset-protocol-scope.cjsandchangeset status: pass (minor).husky/pre-commit: image check,test:unit, the dynamic-import, format-identity and callApi checks,typecheck): pass