Skip to content

[Impl] A schema can't be derived from the tables yet: seven authoring rules and a CI lint would fix that #121

Open

Description

@KonstantinMirin

What did you build?

A validator or schema

What you tried to express, and what happened

Postindustria (IAB Tech Lab member) generated its own schemas from the specification. A deterministic parser reads it, with no model calls. Outputs: JSON Schema 2020-12, rules with test vectors, and TypeScript, Python, and Go types. Inputs: main at 44dfaaf, and with the 14 open PRs, ours included. Generating them shows what the schema README asks implementers to report:

  • Decisions: 45. In 39, the text leaves a point open; 37 of these ask the specification to state something, and say what. The remaining 6 are changes we propose, such as UUIDs for minted IDs.
  • Example failures: The specification's examples fail the generated schemas, or break a generated MUST rule, in 55 places on main and 88 with the open PRs. Most follow the text but not a change we propose. On main, 50 do only that, 4 only disagree with the text, and 1 does both. With the open PRs, these are 78, 9, and 1.
  • Lint findings, by the authoring rule below that removes them. No rule removes a MUST statement naming no field or key: it needs conformance test vectors or binds a party.
Finding main With the open PRs
1. Required column 4 5
2. Object keys 7 7
3. Option types 6 5
4. Value lists 5 9
5. Markers 1 1
6. Paths 4 6
7. Backticked names 6 13
MUST statements naming no field or key 13 26
Other 0 1

Every item: What generating the schemas had to decide.

What you did instead

We recorded each decision; two implementers could decide them differently. To remove the lint findings, we propose seven authoring rules that CI enforces:

  1. Every field and key table has a Required column: REQUIRED, OPTIONAL, or a condition, such as "when basis is spend".
  2. Every Object field has a key table, or links one. No structure lives only in prose.
  3. A selectable or settable row names its option type, such as "available[] of format IDs".
  4. A value list is written once, as `a` | `b`. Other mentions link to it, and an open list says that it is open.
  5. Tables use only the markers § 3 defines.
  6. Paths in prose match the table rows: pricing[].cost_method, not pricing.cost_method.
  7. Every backticked name in normative text resolves to a row or a key, or is listed as an external reference, such as an AdCOM field.

One lint checks all seven, extending scripts/check_appendix.py in validate.yml. Existing findings go on an allowlist that only shrinks, so CI fails only a PR that adds one. We can contribute it as a PR.

Open questions for the working group, as suggestions:

  1. Should money be { amount, currency }, so that an amount never appears without its currency? The generated schemas keep what the text writes: a bare amount beside its currency.
  2. Should each zoned value carry its IANA zone, as { instant, time_zone } or an RFC 9557 string, beyond the line item time_zone that #123 adds? The generated schemas keep RFC 3339 instants. JSON Schema's date-time format doesn't accept RFC 9557's [zone] suffix.

Fields involved

Every field and key table, and prose, mostly in § 2 and § 3.

How blocking was it?

Workaround required, but it works

Before you submit

  • I have read CONTRIBUTING.md and agree my contribution may be published under this repository's licence.
  • This contains no confidential or commercially sensitive information — no real rate cards, deal terms, client names or inventory data.

Revised 2026-10-27: The issue reports what generating the schemas took, and asks about structured money and time. The open-PR input adds our three PRs to the 11 others.

Analyzed and generated with the help of Claude, fully reviewed by me.

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions