Skip to content

Migrate JSON Schema source from draft-07 to 2019-09 (4.0) #3534

Description

@bokelley

Context

PR #3493 introduced core/version-envelope.json and the allOf $ref pattern for envelope-level fields. The composition works correctly under draft-07 because all top-level task envelopes use additionalProperties: true. But it doesn't give us the strictness benefit (unevaluatedProperties: false, draft 2019-09+) that would lock the envelope contract — accidental typos like adp_version validate today.

A schema-draft bump from draft-07 to 2019-09 is the natural follow-up. Because it changes the contract for every external consumer, it belongs at a major-version boundary.

Why 4.0, not 3.x

  • External validators break. Anyone consuming published schemas with a draft-07-locked validator (custom DSP pipelines, in-house compliance tools) errors when source flips. We don't know how many such consumers exist.
  • format semantics change. 2019-09 makes format annotation-only by default. Production validators have to opt back into assertions. That's a behavior shift, not additive.
  • Bundles with other 4.0 cleanups. Legacy version fields go away (adcp_major_version, adcp.major_versions, extensions.adcp.adcp_version). One upgrade window for everyone.
  • Strictness benefit is nice-to-have, not load-bearing. Envelope additionalProperties: true is a deliberate forward-compat choice, not an oversight.

Scope

Source migration:

  • All \$schema declarations: http://json-schema.org/draft-07/schema#https://json-schema.org/draft/2019-09/schema
  • Source files using definitions → migrate to \$defs (4 files identified: brand.json, core/collection-selector.json, core/placement-definition.json, core/x-entity-types.json)
  • Add unevaluatedProperties: false to envelope-style schemas (gains real strictness)

Build pipeline (scripts/build-schemas.cjs):

  • Hardcoded draft-07 at line 326; comments referencing draft-07 semantics at 576/583/840
  • \$defs hoisting logic already exists; verify it works under 2019-09

Test infra:

  • tests/json-schema-validation.test.cjs, tests/composed-schema-validation.test.cjs, tests/media-buy-targeting-overlay-vectors.test.cjs use top-level require('ajv') (defaults to draft-07). Switch to require('ajv/dist/2019').

Dual-shipping plan (uses the v3-after-v4-GA support window, not a separate 3.x experiment):

  • Through 3.x: publish draft-07 only. Source stays draft-07. No build-pipeline change.
  • 4.0 RC window (~2026Q4): publish preview 2019-09 schemas at /schemas/2019-09-preview/...; source migrates to 2019-09; build down-emits draft-07 to existing paths.
  • 4.0 GA: 2019-09 default at /schemas/v4.x/; draft-07 continues at /schemas/v3.x/ for the v3 support window (12 months per cadence policy).
  • Post-v3-EOL: draft-07 emission ends.

Effort estimate

  • ~2 days build pipeline + tests
  • Per-SDK coordination: each downstream SDK (@adcp/client, adcp Python, adcp-go) needs generator pin verified for 2019-09 support. Modern versions of datamodel-code-generator, openapi-typescript, oapi-codegen all handle it.

Out of scope for this issue

  • Migrating to draft 2020-12 (skip a draft, but unevaluated* is what we want; 2019-09 has it).
  • Adding unevaluatedItems: false to array-shape schemas — separate decision.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    claude-triagedIssue has been triaged by the Claude Code triage routine. Remove to re-triage.schemaJSON Schema source-of-truth: definitions, codegen artifacts, validation, hygiene

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions