Skip to content

fix: accept doc_role, SLED delisting and protest fields the API serves - #20

Merged
vdavez merged 1 commit into
mainfrom
fix/api-parity-5.0
Sep 23, 2026
Merged

vdavez merged 1 commit into
mainfrom
fix/api-parity-5.0

Conversation

@makegov-mark

@makegov-mark makegov-mark Bot commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

What

The SDK's client-side shape validator rejected fields the API already serves, and a few protest types and docs did not match the API.

  • attachments(name,doc_role,doc_role_alt) on getOpportunity, listOpportunities, getNotice and listNotices threw ShapeValidationError.
  • delisted_at and meta(jurisdiction_declared) on SLED solicitations threw ShapeValidationError.
  • ProtestRecord typed agency and protester as objects; the API returns strings.
  • getProtest was documented as taking a case number, but the route only accepts the case_id UUID.

How

  • Re-vendored contracts/filter_shape_contract.json for Tango API 5.1.0 and regenerated src/shapes/generatedOverlay.ts.
  • Fixed the overlay generator: when two resources reach the same model's expand (vehicles embed an opportunity), it now merges the two nested schemas instead of letting the later, narrower one replace the earlier one. That replacement is why doc_role stayed missing from the opportunity attachment schema even with a fresh contract. Existing field types are unchanged.
  • Added delisted_at (datetime) and meta.jurisdiction_declared (bool) to the curated SLED schemas, so they get their real types rather than name-heuristic ones.
  • Model types: new OpportunityAttachment and AttachmentDocRole (the six roles), used on Opportunity and Notice; SledOpportunity.delisted_at; SledMetaPayload.jurisdiction_declared; status_reason docs list delisted.
  • ProtestRecord: agency and protester are string | null; added title, docket_url, decision_url, organization, dockets, decisions; deprecated the never-served docket.
  • getProtest(caseId): renamed the parameter, documented the UUID-only route and how to find a case by number. listProtests docs now name GAO, COFC and SBA OHA.
  • Contract appeals and eBuy requests appear in the refreshed contract with no SDK methods yet. Both are mapped to null and baselined as tracked gaps in the two conformance gates.

Testing

  • New tests/unit/client.shape-parity.test.ts shapes attachments(name,doc_role,doc_role_alt) through all four opportunity/notice methods and delisted_at + meta(jurisdiction_declared) through both SLED methods against a stubbed response. All 6 fail on main with ShapeValidationError and pass on this branch.
  • The getProtest test now asserts the request path and string agency/protester.
  • npx vitest run (402 passed), npm run lint, npm run typecheck, npm run build, npm run check-conformance (0 errors), npm run check-shape-coverage (0 new), and a rerun of npm run generate-shape-overlay leaves no diff.

Relationship to #19

This branch conflicts textually with #19 in two places: README.md (the protests/appeals method list) and scripts/check-filter-shape-conformance.ts (contract_appeals: null here vs "listContractAppeals" there). Whichever lands second should keep #19's mapping, drop contract_appeals from both baselines, and rerun npm run generate-shape-overlay. CHANGELOG.md, src/types.ts, src/client.ts and src/shapes/explicitSchemas.ts merge cleanly.

🤖 Generated with Claude Code

Shaping `attachments(name,doc_role,doc_role_alt)` on opportunities and notices, and `delisted_at` or `meta(jurisdiction_declared)` on SLED solicitations, threw `ShapeValidationError` client-side even though the API returns all of them.
The vendored contract is refreshed to Tango API 5.1.0 and the overlay regenerated.
The overlay generator now merges two walks that reach the same model's expand instead of letting the later, narrower one replace the earlier one; that replacement is what dropped `doc_role` from the opportunity attachment schema.
The SLED fields join the curated schemas with their real types, and the model interfaces gain `delisted_at`, `jurisdiction_declared` and a typed `OpportunityAttachment` with the six document roles.

`ProtestRecord` now types `agency` and `protester` as the strings the API returns, and `getProtest` documents that it takes the `case_id` UUID rather than a case number.
Contract appeals and eBuy requests are in the refreshed contract without SDK methods yet, so both are baselined as tracked gaps.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@vdavez
vdavez marked this pull request as ready for review September 23, 2026 13:45
@vdavez
vdavez merged commit d3f8ac3 into main Sep 23, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant