From 3f683ce61d5b93a65145e720ef504ccf6e4dccf6 Mon Sep 17 00:00:00 2001 From: "V. David Zvenyach" Date: Sun, 2 Aug 2026 07:26:33 -0500 Subject: [PATCH] feat(shapes): cover `relationships(type, source)` on entities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tango API 4.20.0 adds two keys to each entry in the entity `relationships` expand — `type` (the stable relationship-type code) and `source` (where the tie came from) — and both are shape-selectable. The SDK's vendored contract predated them, so the shape overlay described the expand as `display_name` / `relation` / `uei` only. Re-vendored the contract and regenerated `tango/shapes/generated_overlay.py`. The only schema delta is the two new leaves on `RELATIONSHIPS_SCHEMA`; the generator produced no other changes across the other 30 containers. Also records the upstream `relation` vocabulary change in the changelog. That needs no SDK code change — `relation` was and remains a `str` — but application code branching on the string `affiliate` should move to `type`. Co-Authored-By: Claude Opus 5 (1M context) --- CHANGELOG.md | 8 ++++++++ contracts/filter_shape_contract.json | 5 +++++ tango/shapes/generated_overlay.py | 2 ++ 3 files changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f00fe73..b47882b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added +- **`relationships(type, source)` on entities.** Tango API 4.20.0 added two keys to each entry in the entity `relationships` expand: `type`, the stable relationship-type code (`prime_sub`, `parent_subsidiary`, `ultimate_parent`, `predecessor`), and `source`, where the tie came from (`sam`, `subawards`). Both are shape-selectable, so `shape="uei,relationships(type,source,uei)"` now resolves against the SDK's schema. Re-vendored the contract and regenerated the shape overlay; the coverage gate reports 0 gaps. + +### Changed +- **The `relation` value vocabulary changed upstream — match on `type` instead.** In Tango API 4.20.0 the `relation` label stopped collapsing to `affiliate` for subcontracting and corporate-succession ties and now names the partner's role: `subcontractor` / `prime`, `predecessor` / `successor`, and `descendant` (rather than `child`) on the far side of an ultimate-parent tie. `affiliate` survives only as a fallback for a type the API doesn't recognize. This affects the large majority of relationship entries. + + No SDK code change is required — `relation` was and remains a `str`. But if you have application code branching on the string `affiliate`, switch it to `type`, which is stable and won't churn again. See the [entities data dictionary](https://docs.makegov.com/data-dictionary/entities/#relationships) for the full vocabulary table. + ## [1.4.0] - 2026-07-20 ### Added diff --git a/contracts/filter_shape_contract.json b/contracts/filter_shape_contract.json index 966ae93..ad569c8 100644 --- a/contracts/filter_shape_contract.json +++ b/contracts/filter_shape_contract.json @@ -1,5 +1,6 @@ { "meta": { + "api_version": "4.20.0", "description": "Canonical API filter/shape contract. Downstream consumers (SDK, MCP) should validate their conformance against this manifest.", "generated_from": "scripts/filter_shape_conformance.py", "schema_version": 2 @@ -2511,6 +2512,8 @@ "fields": [ "display_name", "relation", + "source", + "type", "uei" ] }, @@ -2685,6 +2688,8 @@ "relationships", "relationships.display_name", "relationships.relation", + "relationships.source", + "relationships.type", "relationships.uei", "sam_activation_date", "sam_expiration_date", diff --git a/tango/shapes/generated_overlay.py b/tango/shapes/generated_overlay.py index 4a93d0f..2b0d47f 100644 --- a/tango/shapes/generated_overlay.py +++ b/tango/shapes/generated_overlay.py @@ -716,6 +716,8 @@ RELATIONSHIPS_SCHEMA: dict[str, FieldSchema] = { "display_name": FieldSchema(name="display_name", type=str, is_optional=True, is_list=False), "relation": FieldSchema(name="relation", type=str, is_optional=True, is_list=False), + "source": FieldSchema(name="source", type=str, is_optional=True, is_list=False), + "type": FieldSchema(name="type", type=str, is_optional=True, is_list=False), "uei": FieldSchema(name="uei", type=str, is_optional=True, is_list=False), }