Real-world examples: overview¶
Four real, external formats — none designed for Omnist — each run through the whole pipeline: an OSD schema, real fixtures, validation, OML output. Together they're a stress test of the codecs and a candid account of what OSD's schema algebra can and can't express, across formats with very different amounts of design discipline behind them.
| Example | Format | Spec rigor | Fields | Closed | any |
any % |
Gaps exercised |
|---|---|---|---|---|---|---|---|
| pyproject.toml | TOML | Multiple PEPs (517/621/639/794) | 20 | 13 | 7 | 35% | Union, open key set, cross-field |
| package.json | JSON | None — prose docs only, third-party schema | 16 | 8 | 8 | 50% | Union, open key set |
| GitHub Actions workflow | YAML | None — prose docs only, third-party schema | 8 | 2 | 6 | 75% | Union (3-way), open key set, shape-depends-on-sibling-key |
| sitemap.xml | XML | One small, official XSD spec | 4 | 4 | 0 | 0% | Value refinement (enum/range) |
All four counts are computed directly from the schemas by
tests/test_examples_*.py, not typed by hand — the table above can't
silently drift from what parse_schema actually reports.
The spec-rigor spectrum¶
Ordered by how much formal ground truth each format actually has: pyproject.toml (several numbered PEPs, each enumerating exact field shapes) → sitemap.xml (one small, official, narrow XSD) → GitHub Actions workflows (a community-maintained schema only, never an official GitHub artifact, though you can at least observe real CI runs to check behavior) → package.json (no spec and no official schema at all — just years of accreted convention).
The any proportion doesn't track schema size or effort — it tracks
where a format sits on this spectrum. pyproject.toml has the most
fields and the lowest any fraction; the GitHub Actions workflow
schema is the smallest of the four by field count and still comes out
worst, because jobs: alone is irreducibly open and carries most of a
workflow's real content. Sitemap.xml, the most formally specified
format after pyproject.toml, is the only one of the four with zero
any fields at all.
The four gap categories, one worked example of each¶
- Union — a field that's legitimately more than one shape.
pyproject.toml'slicense(a string or a table) is the simplest case; GitHub Actions'on(string, array, or map) is the sharpest, a genuine three-way union. OSD's field type is always exactly one scalar or oneRef— there's no "A or B" combinator. - Open key set — a record where the label set isn't fixed by the
format, it's chosen by whoever writes the file.
[tool]in pyproject.toml,dependenciesin package.json,jobsin GitHub Actions workflows. OSD records are closed by design — see the openness design record for why that's deliberate, not an oversight. - Cross-field constraint — a rule spanning sibling fields, like
pyproject.toml's
versionbeing required unless"version"appears indynamic. OSD's cardinality is per-field only. - Value refinement — a field with the right type but a
restricted value set or range. Only sitemap.xml surfaced this:
changefreqrestricted to 7 enumerated strings,priorityrestricted to[0.0, 1.0]. It took the cleanest, most tightly specified format in the set to expose this gap — the messier formats never got clean enough to show it on its own.
If you're designing a format for OSD¶
Lessons drawn from all four examples, not just pyproject.toml:
- Avoid same-key polymorphism.
readme/license(pyproject.toml) andauthor/bugs/repository(package.json) being a string or a table under one key is the single biggest source of unchecked surface across this whole set. If a format needs both a short and a long form of something, use different keys, not one polymorphic key. - Hoist open keys into their own namespace.
[tool]in pyproject.toml does this correctly — all openness lives in one dedicated, clearly-open section.urls/scripts/entry-pointsscattered through pyproject.toml's otherwise-closed[project]table, and GitHub Actions'jobs/env/defaultsmixed alongside closed fields likename, don't. If part of a structure needs arbitrary keys, give it its own top-level section. - Avoid conditional requiredness across sibling fields ("at least one of A or B," "A required unless B says otherwise"). Pick one canonical, always-required field instead of an either/or.
- Avoid meta-referential fields — a field whose value names
other fields and changes their shape or requiredness.
pyproject.toml's
dynamic(a list of field names that make those fields optional) and GitHub Actions'steps:(each item's shape depends on whetheruses:orrun:is present) are both instances of this. No static schema language can express it; it requires runtime interpretation of the data to know what shape is even expected. - If you need restricted values, say so in the spec explicitly, and
expect most schema languages to only enforce the type, not the
restriction. sitemap.xml's
changefreq/priorityshow this isn't even about open-endedness — a small, fully closed format can still have unchecked value constraints if the schema language it's checked against has no enum or range type. - Silent forward-extension of a closed section is a versioning
problem, not a modeling one. pyproject.toml's
import-names/import-namespacesarriving after the fact is the example here — if a section needs to grow over time, decide upfront whether it's genuinely closed (and accept that growth needs an explicit version marker) or genuinely open (and give it its own namespace from day one).
The common thread: OSD models cleanly whatever a format's design keeps structurally uniform, value-restricted where it matters, and unconditional. Every gap in this set traces back to a format that didn't hold one of those three lines — usually because its real validator is prose plus executable code, which was never forced to commit to them in the first place.
All four fixtures already carry the kind of long, repeated-label lists
OML array syntax (issue #218) exists for —
pyproject.toml's classifiers/keywords, sitemap.xml's repeated url
entries, package.json's dependency lists, and GitHub Actions' step
sequences are all cases where write_oml(node, arrays=True)'s
label: [v1, v2, ...] form reads more like the source format than a long
run of repeated label: v edges does.
Read the four in order¶
- pyproject.toml — the most formally specified format in the set; the baseline for all three gap categories before value refinement.
- package.json — no spec at all; a smaller schema
with a higher
anyfraction than pyproject.toml's, showing the proportion tracks the format's own rigor, not schema size. - GitHub Actions workflow — the worst
anyfraction of the four, plus a real codec-level finding (YAML 1.1's boolean-coercion rule breaking the ordinaryon:key). - sitemap.xml — the clean contrast case, and the one that surfaces the fourth gap type the other three couldn't.