feat: add AAO geo metro reference registry (nielsen_dma)#5627
feat: add AAO geo metro reference registry (nielsen_dma)#5627nastassiafulconis wants to merge 7 commits into
Conversation
…docs
Adds the first AAO-maintained geo metro reference registry:
- JSON schema defining the registry entry shape (code, name, aliases, deprecation)
- Initial nielsen_dma data file with ~90 US markets and common aliases
- Reference docs explaining agent usage patterns (name->code and code->name)
The registry addresses a gap in AdCP: the protocol names metro systems
(nielsen_dma, uk_itl1, etc.) in metro-system.json and get_adcp_capabilities,
but provides no authoritative code-to-name lookup. Agents without this
resolve market names from training data and hallucinate codes.
Server endpoint (GET /api/reference/geo-metros/{system}) to follow.
There was a problem hiding this comment.
Request changes. The registry's whole job is to stop agents resolving market names from hallucinated codes — and the data it ships is hallucinated codes. Two blockers below, both with a named failure mode.
MUST FIX
1. The nielsen_dma codes are fabricated and contradict authoritative Nielsen data and this repo's own docs. geo-metro-nielsen_dma.json numbers markets sequentially from 501 by market rank — 502 → Los Angeles, CA, 503 → Chicago, IL, 505 → Dallas-Ft. Worth, 506 → San Francisco. Real Nielsen DMA codes are non-contiguous: Los Angeles is 803, Chicago is 602, Dallas-Ft. Worth is 623, SF is 807. This isn't a guess — docs/reference/migration/geo-targeting.mdx:58 already documents 602 (Chicago) and :170 targets 803 (Los Angeles), and tests/example-validation.test.cjs:163 uses 602. So the registry directly contradicts published examples already in this repo. Adopter failure in one sentence: an agent resolving "Chicago" off this table writes 503 into geo_metros.values[] and silently misdirects spend to Macon, GA (real DMA 503). Only 501 → New York happens to be correct because rank #1 and code 501 coincide. The entire code column from 502 down must be regenerated from the authoritative Nielsen DMA list and reconciled with geo-targeting.mdx. ad-tech-protocol-expert: unsound — cited divergence at geo-metro-nielsen_dma.json entries 502/503 vs geo-targeting.mdx:58,170.
2. The data file is a bare instance with no $schema, and it breaks the schema-validation suite. tests/schema-validation.test.cjs:107 treats every .json under static/schemas/source/** as a JSON Schema; validateSchemaStructure (:119-133) returns Missing $schema field and Test 1 fails. The sibling v1-canonical-mapping.json does not hit this because it is a self-describing schema — $schema/$id/title/description present, data folded under a mappings property. This PR claims to follow that governance pattern but inverted it: it shipped raw data into a directory the test harness reads as schemas. Either make the data file self-describing (mirror v1-canonical-mapping.json) or exclude registries/geo-metro-{system}.json from findAllSchemas and add a dedicated test that validates the data against geo-metro-registry.json. Right now test:schemas is red.
Things I checked
geo-metro-registry.jsonthe schema itself is the right shape — draft-07,$idrelative,system$refs/schemas/enums/metro-system.jsonexactly ascore/targeting.json:50does, nooneOfintroduced (no discriminator-audit concern). The Albany 525/532 ambiguity handling is load-bearing and correct across schema, data, and docs.- No wire-shape drift on
geo_metros—{system, values[]}percore/targeting.jsonis unchanged. The break is in the values, not the envelope. - Changeset present with empty frontmatter — correct per repo convention for a non-package-bumping change (matches
5595-addie-explicit-org-selection.md). Not a defect. metro-system.jsonenum carries all four documented systems pluscustom. Enum alignment clean.
Follow-ups (non-blocking — fix alongside the blockers)
package-lock.jsonis unrelated churn — drop it.package.jsonis untouched, yet the lockfile togglespeer: trueacross ~15 packages (express, pg, hono, zod,@modelcontextprotocol/sdk) and removesproxy-agent/quickjs-wasi. Signature ofnpm installunder a different npm version, not a dependency change.git checkout origin/main -- package-lock.jsonand re-push; the feature needs zero lockfile changes.digest: "". Schema marksdigestrequired and the docs build the entire caching contract on it (sha256 of entries). Shipping empty means every version keys to the same digest and staleness detection never fires. Compute it, or relaxrequiredand note that the serving layer computes it at emit time.- Endpoint documented as live.
geo-metro-registry.mdx:39,99-131presentsGET /api/reference/geo-metros/{system}with request/response examples, but the PR body says the endpoint is a follow-up. Mark it forthcoming and point readers at the static file. - Orphan page.
geo-metro-registry.mdxis not registered indocs.jsonnav — it won't appear in the sidebar.
Minor nits (non-blocking)
- Coverage overclaim.
geo-metro-registry.mdx:67saysnielsen_dmacovers "~210 US designated market areas"; the file ships ~93. The PR body honestly says "~90." Qualify it ("~90 of ~210; initial set") so absence-of-code doesn't read as invalid-market. The ITL/NUTS rows describe registries that 404 today — mark them planned. broken-linksis red, PR-caused.geo-metro-registry.mdx:45uses a bare versionless[...](/schemas/registries/geo-metro-registry.json);lint-schema-links --checkrejects it. Use thehttps://adcontextprotocol.org/schemas/v3/registries/...form likecanonical-formats-migration.mdx:112.npm run fix:schema-linksfixes it.check-seois red, PR-caused.check-seo-metadata.cjsrequiresog:titleto start withAdCP; this doc's is"Geo Metro Registry — AdCP Reference".
The schema design is sound and the problem this solves is real. Fix the codes against the authoritative Nielsen list, make the data file survive the test harness, and this is a clean first registry. I'll re-review on the codes plus a green test:schemas.
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
There was a problem hiding this comment.
Clean additive registry. Right shape: a versioned, content-digested reference table that lets agents resolve market names to codes instead of hallucinating "Albany" into the wrong DMA — and it parallels the existing v1-canonical-mapping.json governance pattern exactly.
Things I checked
- Non-breaking on the wire. No change to
enums/metro-system.json,core/targeting.json(geo_metros), or the capabilities response. The registry is a side-channel reference resource, not part of the bid/targeting shape. (ad-tech-protocol-expert: sound-with-caveats.) - Schema
$refis correct.geo-metro-registry.json:9references/schemas/enums/metro-system.json, which exists and carriesnielsen_dma— same refcore/targeting.jsonuses. No oneOf anywhere in the diff, so no discriminator concern. - Data validates against the schema. 97 entries, all required fields present, no
additionalProperties:falseviolations, codes unique and strictly ascending. (code-reviewer: ready to push, no blockers.) - Build pipeline is safe.
build-schemas.cjs:984-995only rewrites"$id"/"$ref"/"$schema"keys followed by/schemas/. The data file carries none of those, so codes like"501"and thesource_urlpass through unmangled. Registries aren't bundled (only request/response patterns are), so the data file copies through as a static artifact — same precedent asv1-canonical-mapping.json. - Changeset present and conventional. Empty
---/---frontmatter matches the established repo pattern (identical to the just-merged5595-addie-explicit-org-selection.md). Not a missing changeset.
Follow-ups (non-blocking — file as issues)
- Docs read as if the endpoint is live.
geo-metro-registry.mdxdocumentsGET /api/reference/geo-metros/{system}with a concrete request/response and the agent-usage steps are written around "fetch the registry" — but the PR body defers the endpoint to a follow-up. An agent following these instructions today gets a 404. Add a<Note>that the endpoint isn't live yet and the file is consumed from the repo for now. This is the one I'd land first. - Coverage claim overstates what ships.
geo-metro-registry.mdx:62listsnielsen_dmaas "~210 US designated market areas"; 97 ship. By the doc's own code→name step 3, an agent treats a missing market as "deprecated or provider-custom" rather than "registry incomplete" — the exact silent-misdirection this registry exists to prevent. Reword to "~90 major markets (partial; expanding)," and mark the three unshipped systems (uk_itl1/uk_itl2/eurostat_nuts2) as planned — the "Long-term Direction" section already says so, so the table contradicts it. countryenforcement is prose-only. The schema description sayscountryis "Required for non-US systems" but it's not inrequiredand there's no conditional. Fine for a US-only seed; before a non-US data file lands, add a root-system-keyedallOfor a CI lint so the constraint doesn't rot.- Doc field tables drift from schema. Entry table omits
region/country/deprecated_reason; registry table omitslast_updated(required) andsource_url. Fill them so the tables are a faithful projection.
Minor nits (non-blocking)
- Empty digest.
geo-metro-nielsen_dma.json:5ships"digest": "". Schema-valid (present string), but the schema and docs both describedigestas the sha256 clients use for cache validation — an empty value defeats that, and two versions could both present"". Populate it before the endpoint ships, or add a$commentthat it's computed at publish time so a future reviewer doesn't read""as steady-state. - Not in nav.
geo-metro-registry.mdxisn't registered indocs.json— it'll render but won't appear in site navigation. Add an entry if it's meant to be discoverable.
The schema contract and data are the load-bearing part of this PR and they're clean. The doc drift is real but it's prose against a deferred endpoint — fix it before the endpoint PR, not before this one.
LGTM. Follow-ups noted below.
There was a problem hiding this comment.
Request changes. The schema is the right shape and follows the v1-canonical-mapping.json governance pattern cleanly — but the nielsen_dma data file ships fabricated codes for the highest-traffic markets, which manufactures the exact misdirected-spend failure this registry exists to prevent.
MUST FIX (blocking)
The DMA codes in geo-metro-nielsen_dma.json are wrong for the top markets. Nielsen DMA codes are a fixed, non-sequential numbering scheme. This file assigns them sequentially in market-rank order (501, 502, 503…), which is definitionally not how Nielsen numbers DMAs. New York (501) and Philadelphia (504) happen to line up; the rest of the top block does not. Verified corrections:
| File | code → name claimed | Actual Nielsen DMA |
|---|---|---|
geo-metro-nielsen_dma.json:9 |
502 → Los Angeles |
LA is 803; 502 is Binghamton, NY |
geo-metro-nielsen_dma.json:10 |
503 → Chicago |
Chicago is 602; 503 is Macon, GA |
geo-metro-nielsen_dma.json:12 |
505 → Dallas-Ft. Worth |
Dallas is 623; 505 is Detroit |
geo-metro-nielsen_dma.json:13 |
506 → San Francisco |
SF is 807; 506 is Boston |
geo-metro-nielsen_dma.json:14 |
507 → Boston |
Boston is 506; 507 is Savannah |
geo-metro-nielsen_dma.json:15 |
508 → Washington, DC |
DC is 511; 508 is Pittsburgh |
geo-metro-nielsen_dma.json:16 |
509 → Atlanta |
Atlanta is 524; 509 is Ft. Wayne |
geo-metro-nielsen_dma.json:17 |
510 → Houston |
Houston is 618; 510 is Cleveland-Akron |
geo-metro-nielsen_dma.json:18 |
511 → Seattle-Tacoma |
Seattle is 819; 511 is Washington DC |
geo-metro-nielsen_dma.json:88 |
602 → Phoenix |
Phoenix is 753; 602 is Chicago |
What breaks for adopters: an agent trusts the registry, a buyer says "target Los Angeles," the agent resolves to `502`, and the campaign runs in Binghamton, NY. A registry that authoritatively returns wrong codes is strictly worse than no registry — it launders a flagged hallucination into a trusted, silent error. The file's own `source_url` (`nielsen.com/dma-regions`) does not produce these values.
The mid-band entries that prove the point are correct — `525` Albany, GA, `531` Tri-Cities, `532` Albany-Schenectady-Troy all check out, including the Albany pair the PR is built around. That's the signature of a real list for the obscure markets and memory-filled rank codes for the famous ones.
Required before merge: regenerate `geo-metro-nielsen_dma.json` from the primary Nielsen DMA publication and cross-check the majors (LA 803, Chicago 602, Dallas 623, SF 807, Detroit 505, Boston 506, DC 511, Atlanta 524, Houston 618, Seattle 819, Phoenix 753). `ad-tech-protocol-expert`: unsound — top-block codes diverge from the authoritative Nielsen numbering.
Things I checked
- `system` `$ref` → `/schemas/enums/metro-system.json` resolves; the enum carries `nielsen_dma`. Sibling `description` alongside `$ref` is draft-07-legal and matches existing repo convention (`context-match-request.json` does the same against the same enum). Sound.
- `GeoMetroEntry` is `additionalProperties:false`, `required:[code,name]` — clean closed shape, no `oneOf`, no discriminator regression.
- Build pipeline: `scripts/build-schemas.cjs` copies `registries/*.json` verbatim and never Ajv-compiles them; `registries/` is not in `bundlePatterns`. The data file having no `$schema`/`$id` won't choke the build. No CI break.
- Changeset present with empty `---/---` frontmatter — matches the established `.changeset/5595-addie-explicit-org-selection.md` "empty changeset" convention; `changeset version` treats it as a no-op note. Adequate.
- `code-reviewer`: clean on build/CI, no blockers from the tooling side.
Follow-ups (non-blocking — file as issues)
- Empty `digest`. `geo-metro-nielsen_dma.json:5` ships `"digest": ""` while the schema marks it `required` and the docs define it as sha256-of-`entries` for cache validation. It passes `type:string` but is semantically dead — clients keying cache off `digest` see every fetch as identical. Note the divergence from `v1-canonical-mapping.json`, which does not make `digest` a schema field and computes it at emit time. Pick one model: drop `digest` from `required` and compute server-side, or populate it. Don't ship required-but-empty.
- Coverage drift. `geo-metro-registry.mdx:55` advertises "~210 US designated market areas" but the file ships ~90. Reconcile the doc to "initial ~90, expanding to ~210" or fill the file.
- Docs describe an endpoint that doesn't exist. `geo-metro-registry.mdx:42,103` document `GET /api/reference/geo-metros/{system}` as live. The PR body flags the endpoint as a follow-up — carry that caveat into the page so a reader doesn't treat it as shipped.
- Orphan nav. The new `.mdx` is not wired into `docs.json`. Reachable by URL, not by nav.
Minor nits (non-blocking)
- The marquee "Albany" example doesn't fire on the shipped data. Docs (`geo-metro-registry.mdx:97`) lean on "Albany" matching both 525 and 532. But `525` has empty `aliases` and `532` carries `"Albany NY"`, not bare `"Albany"` — a literal case-insensitive "Albany" match hits neither cleanly. Add `"Albany"` to 532's aliases (and arguably 525's) or the centerpiece ambiguity demo is fiction against the data.
- Changeset body skips the `Empty changeset:` prefix the convention uses. Cosmetic.
Fix the codes and this is a clean, well-modeled addition. The schema work is right; the data has to be right too, because "authoritative" is the entire pitch.
There was a problem hiding this comment.
Request changes. The data file ships wrong Nielsen DMA codes, and a wrong authoritative lookup table is worse than none — agents will trust it and misdirect spend, which is the exact hallucination this registry exists to prevent.
The block: codes are numbered by market-size rank, not Nielsen DMA codes
static/schemas/source/registries/geo-metro-nielsen_dma.json numbers the top markets sequentially from 501 instead of using real DMA codes. This contradicts the repo's own published examples:
docs/media-buy/advanced-topics/targeting.mdx:410,435,532use602for Chicago and803for Los Angeles.- This PR maps
602→ "Phoenix (Prescott), AZ" and assigns Los Angeles to502, omitting803entirely.
Spot-checked, high confidence, corroborated by the targeting docs and well-established DMA assignments:
505→ "Dallas-Ft. Worth" — 505 is Detroit. Dallas is 623.506→ "San Francisco-Oakland-San Jose" — 506 is Boston (Manchester). SF is 807.507→ "Boston (Manchester)" — 507 is Savannah.508→ "Washington, DC" — 508 is Pittsburgh. DC is 511.602→ "Phoenix" — 602 is Chicago (per this repo's own targeting examples).
What makes it dangerous, not merely incomplete: a few entries are correct (501 New York, 504 Philadelphia, 525 Albany GA, 532 Albany-Schenectady-Troy NY). Partial correctness earns false trust. An agent resolving "target Chicago" writes 602 correctly; an agent rendering stored code 602 against this registry displays "Phoenix" — and an agent resolving "Los Angeles" writes 502 instead of 803. Silent misdirection of spend, on the table whose whole job is to stop that.
Re-derive the full set from an authoritative Nielsen DMA source and verify against targeting.mdx. Don't patch row by row — the pattern says the whole 5xx block is suspect.
Things I checked
systemenum reference is sound —geo-metro-registry.json$refs/schemas/enums/metro-system.json, which carriesnielsen_dma. Same$refthegeo_metroswire field uses. Right shape (ad-tech-protocol-expert: sound-with-caveats).- Purely additive on the wire. Nothing in
geo_metros(static/schemas/source/core/targeting.json:44-67), the enum, or any task shape changed. No major changeset required; the empty-frontmatter changeset matches repo convention (.changeset/5595-addie-explicit-org-selection.md). - Registries-dir precedent confirmed:
static/schemas/source/registries/v1-canonical-mapping.json. Note that file is a real JSON Schema; this PR'snielsen_dma.jsonis a data instance — see follow-up below. - No oneOf added —
scripts/oneof-discriminators.baseline.jsonuntouched. - No duplicate codes in the data file;
entrieshonors "ordered by code ascending." codeis correctly specified as an opaque string ("do not cast to integer"), matchinggeo_metros.values[]semantics.
Follow-ups (non-blocking — file as issues)
- Data file published as an always-valid no-op schema.
scripts/build-schemas.cjsandtests/schema-validation.test.cjscompile every.jsonunderstatic/schemas/source/**as a JSON Schema.geo-metro-nielsen_dma.jsonis a data instance — withstrict:false, ajv treatssystem/version/entriesas unknown keywords and compiles a schema that validates everything. CI stays green, but it publishes a meaningless schema at/schemas/v3/registries/geo-metro-nielsen_dma.json. Unlikev1-canonical-mapping.json(a genuine schema), this is data wearing a$schemaheader. Store the data where the build doesn't compile it as a schema, or accept that the bundled artifact is a no-op. Worth resolving before the follow-up endpoint PR consumes it. - Partial coverage. Docs claim "~210 US DMAs"; the file ships ~97. Read-direction lookups for omitted common markets fall through to raw-code display; write-direction fails to resolve them. State the partial scope in the data file/docs.
region/country"Required for non-US systems" is documented but unenforced — noif/then. Fine for nielsen_dma (US); add the conditional when uk_itl/nuts files land.
Minor nits (non-blocking)
digestshipped as"".geo-metro-nielsen_dma.json:9. The schema marksdigestrequired and defines it as sha256-of-entries; the docs tell clients to cache-invalidate on it. Empty string passestype:stringbut makes the documented cache contract a no-op and gives a false integrity signal. Either compute it at publish time (with a build check that it matchessha256(entries)) or drop it fromrequireduntil the pipeline fills it. Required-and-meaningless is the worst of both.- Hardcoded
/schemas/v3/indocs/reference/geo-metro-registry.mdx:34. Confirm v3 is the live major.
Re-derive the codes against an authoritative source and targeting.mdx, and this is a clean, well-shaped addition. The schema design and governance prose are right.
- Replace fabricated sequential codes with verified Nielsen DMA codes: removed the rank-order top-market codes (502=Binghamton not LA, 503=Macon not Chicago, etc.) and replaced with correct codes per reviewer corrections and this repo's own targeting.mdx examples (602=Chicago, 803=LA, 807=SF, 819=Seattle, 753=Phoenix, etc.) - Compute and populate sha256 digest of entries array - Mark GET /api/reference/geo-metros endpoint as planned, not live - Fix coverage claim: ~27 verified markets (not ~210) - Fix Albany ambiguity example: add 'Albany' alias to both DMA 525 and 532 - Add page to docs.json nav under Reference - Prefix changeset body with 'Empty changeset:' per repo convention
There was a problem hiding this comment.
Additive registry, correct shape, no wire impact. New schema plus new reference data that feeds the existing geo_metros contract — nothing published changes, so this is the right way to ship a shared lookup table.
Things I checked
- Enum alignment.
geo-metro-registry.jsontypessystemas$ref: /schemas/enums/metro-system.json. That enum is["nielsen_dma","uk_itl1","uk_itl2","eurostat_nuts2","custom"]—nielsen_dmais in it. No enum drift, no new undiscriminatedoneOf, audit walker unaffected. codeis the right shape. Typedstringwith "do not cast to integer," matchingtargeting.jsongeo_metros.values[](string array). On the wire the registrycodeand the targeting value are the same opaque identifier. Good.- DMA codes are the real numbering. The commit-7 correction replaced the fabricated rank-order codes (502=LA, 503=Chicago) with the actual non-sequential Nielsen scheme: 505=Detroit, 508=Pittsburgh, 602=Chicago, 618=Houston, 623=Dallas-Ft. Worth, 753=Phoenix, 803=LA, 807=SF, 819=Seattle. Spot-checked 17 — all correct. The load-bearing disambiguation (525=Albany, GA vs 532=Albany-Schenectady-Troy, NY) is intact, and both now carry the
Albanyalias so the documented ambiguity actually fires. - Entries ordered ascending. 501 → 819, 27 entries, strictly ascending per the schema description.
- Validates against its own schema. Every entry has required
code+nameand onlycode/name/aliases— satisfiesadditionalProperties:falseonGeoMetroEntry. Top-level requiredsystem/version/last_updated/digest/entriesall present. - Build doesn't choke.
build-schemas.cjscopiessource/registries/*.jsonwithout dereferencing (registries/is outsidebundlePatterns);schema-validation.test.cjscompiles the data file as a permissive draft-07 schema (unknown keywords ignored understrict:false).v1-canonical-mapping.jsonis the precedent in the same dir. - Changeset. Empty changeset (
---\n---, bodyEmpty changeset:) matches the established convention (see 5595) and passescheck-changeset-protocol-scope.cjs—static/schemas/source/**anddocs/reference/**are protocol-scoped, so empty is valid for a non-wire-breaking addition.
Follow-ups (non-blocking — file as issues)
digestis decorative until something computes it. Schema says "sha256 ofentriesserialised with sorted keys, hex-encoded" but pins no serializer (JSJSON.stringifysorted vs Pythonjson.dumps(sort_keys=True)differ on whitespace/separators), and no test recomputes or asserts2e2fb3ca…3334. Two conformant clients can disagree. Pin the algorithm and add a build-time assert when theGET /api/reference/geo-metros/{system}endpoint lands.- Nothing validates the data file against the registry schema in CI. Conformance here is by convention. When the endpoint PR arrives, wire a test that validates each
geo-metro-{system}.jsonagainstgeo-metro-registry.json. - Confirm 543 = Springfield-Holyoke, MA against the Nielsen reference before the seed expands — it's the one mapping flagged as worth a second source (543 is occasionally confused with the NC market). Reads correct to me, but cheap to verify now.
Minor nits (non-blocking)
- Field table omits
source_url.geo-metro-registry.mdxdocuments the registry-level fields but skipssource_url, which is a real schema property and is populated in the data file. Governance prose references "the source system's authoritative publication" without naming the field that carries it. - Abbreviated example drops two required fields. The docs sample object has
system/version/entriesbut omitslast_updatedanddigest, bothrequired. Fine as an abbreviation, but the page elsewhere stresses both — an agent copying the shape emits an invalid file.
The endpoint isn't here, so the primary user-facing path — agents actually fetching nielsen_dma over HTTP — ships unvalidated. That's by design per the PR description and the docs <Note>, and the data is consumable from the repo today, so it doesn't block. First of a class is the right time to get the digest contract pinned before three more systems inherit it.
Approving on the strength of the corrected DMA data plus the clean additive surface. Follow-ups noted.
|
Closing — after working through this, a protocol-owned canonical geo-metro table is the wrong layer. AdCP should own identity (the code, already lossless on the wire) and the resolution contract, not the corpus. The name is a rendering concern: render at the edge from a lookup you already hold, never reconstruct from training data. Cross-party display is already covered by A central AAO table also carries Nielsen IP and stale-but-signed risk — this PR shipped fabricated codes in its first commit, caught only by review. Recorded the decision and the small buyer-side refinement in scope3data/agentic-api#4576. Thanks for surfacing the real problem — it's worth fixing, just one layer down. |
…e, not the corpus) (#5708) Adds supporting principle 8 to design-principles.mdx: AdCP owns the namespace and the resolution contract for reference data, not the underlying code↔name corpus, unless AdCP itself mints the values. Codifies the boundary surfaced by the declined geo-metro registry proposal (#5627) so future reference-data RFCs (postal, places, app/property lists) are decided by the rule rather than re-litigated. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Why
AdCP names metro classification systems (
nielsen_dma,uk_itl1, etc.) inmetro-system.jsonand surfaces them throughget_adcp_capabilities, but provides no authoritative code-to-name lookup. Agents without this resolve market names from training data and hallucinate — "Albany" could be DMA 525 (Albany, GA) or DMA 532 (Albany-Schenectady-Troy, NY), and getting it wrong silently misdirects spend.This is the first of a class of shared reference registries that AAO should maintain for data that is standardized across sellers, needed for natural-language resolution, and painful for every provider to ship independently.
What Changed
static/schemas/source/registries/geo-metro-registry.json— JSON schema defining the registry file shape: versioned, content-digested entries withcode,name,aliases[], and deprecation fields. Follows the same governance pattern asv1-canonical-mapping.json.static/schemas/source/registries/geo-metro-nielsen_dma.json— Initialnielsen_dmadata file with ~90 US markets and common aliases (including ambiguous cases like "Albany" → DMA 525 vs 532).docs/reference/geo-metro-registry.mdx— Reference docs covering agent usage patterns (name→code write direction, code→name read direction, ambiguity handling, caching).What's Not Here
Server endpoint (
GET /api/reference/geo-metros/{system}) — follow-up PR. This PR establishes the schema contract and data; the endpoint implementation can be reviewed separately.ITL and NUTS data files for
uk_itl1,uk_itl2,eurostat_nuts2— follow-up PRs once the schema is agreed.Related
Scope3 Interchange PR that prompted this: https://github.com/scope3data/agentic-api/pull/3990