Repository navigation
fix(shapes): accept doc_role and the post-launch SLED fields the API serves - #66
Merged
Merged
Conversation
…serves Shapes naming `attachments(doc_role, doc_role_alt)` on opportunities and notices, or `delisted_at` / `meta(jurisdiction_declared)` on SLED solicitations, raised `ShapeValidationError` after the request had already been made, although the API returns all four. Re-vendors the filter/shape contract (Tango API 5.1.0) and regenerates the shape overlay from it. Re-vendoring alone did not fix opportunities: the overlay generator let the vehicles resource's `opportunity` embed, which exposes fewer attachment fields, replace the opportunity resource's own `attachments` schema. The generator now adds the missing fields instead of replacing the schema, and keeps every existing field's type. Adds observed types for the SLED resources, which the type probe predates, so the overlay stops guessing them from field names: the date fields parse to `datetime`, `category_codes` / `attachments` / `revisions` are lists, and the flags, sizes and counts are booleans and integers. Adds `delisted_at` to both SLED default shapes, matching the API's list default, and documents the new fields. Corrects the protest docstrings and API reference: three venues (GAO, COFC, SBA OHA), `naics_code` is the SBA OHA code at issue, and `case_number` examples cover each venue. Baselines `contract_appeals` and `ebuy/requests` as unmapped resources in the shape-coverage gate. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
vdavez
marked this pull request as ready for review
September 23, 2026 13:24
This was referenced Sep 23, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Brings the SDK's shape schema up to what the Tango API serves today.
Four fields the API returns were rejected client-side with
ShapeValidationError, after the request had already been made:attachments(doc_role, doc_role_alt)on opportunities and notices (Pro plan and above).delisted_atandmeta(jurisdiction_declared)on SLED solicitations.Changes
contracts/filter_shape_contract.json(Tango API 5.1.0) withscripts/refresh_contract.pyand regeneratedtango/shapes/generated_overlay.pywithscripts/generate_shape_overlay.py. Neither file is hand-edited.doc_rolevalidate on opportunities. An opportunity is reachable from its own resource and as theopportunityexpand on vehicles, and the generator let whichever tree it walked last replace the other; the vehicles embed exposes fewer attachment fields, so it hid fields the opportunity endpoint serves. The generator now adds the missing fields instead of replacing the schema, and the later tree still decides every field both define. I diffed every resolved schema path againstmain: outside SLED, no existing field's type or list-ness changed; the only additions are the four fields above.contracts/observed_shape_types.json. The type probe predates SLED, so the overlay had guessed SLED types from field names. The entries come from sampling the live API, cross-checked against the API's model definitions where the sample misread a value (a numeric-looking solicitation number, an all-nulldelisted_at). This fixes the mismatches:meta(last_change_source_declared)is a boolean,attachments(size_bytes, pages)are integers,category_codesis a list of objects, and the date fields parse todatetimerather than a truncateddateor a string.delisted_atjoins both SLED default shapes, matching the API's own list default, and is documented onSledOpportunityalong withmeta.jurisdiction_declared.docs/API_REFERENCE.md;naics_codeis the NAICS code at issue in an SBA OHA appeal, not the solicitation's;case_numberexamples cover each venue;naics_codeadded to the documented filters.Opportunity/Noticeand indocs/API_REFERENCE.md: the six values, that they must be named, and that an unclassified attachment omits the keys.contract_appealsandebuy/requestsas unmapped resources, since the SDK does not wrap either yet.Behavior change worth reading
SLED values now carry the API's types.
posted_date,response_deadline,response_deadline_originalandbid_opening_dateparse to timezone-awaredatetimevalues, where before two were truncated todateand two stayed strings. Code comparing them as strings needs to comparedatetimevalues. This is in the changelog under Changed.Relationship to other PRs
delisted_aton the schema and both default shapes,meta(jurisdiction_declared), the docs rows) from a newer contract, and typesjurisdiction_declaredas a boolean where feat(sled): add the delisted_at field the API returns #64's regenerated overlay typed it as a string.contracts/filter_shape_contract.json,tango/shapes/generated_overlay.pyandCHANGELOG.md. Rebasing it on this and re-running the refresh and generator scripts resolves the first two. Once feat(contract-appeals): add the contract appeals resource #65 maps the resource, it should drop thecontract_appealsline this PR adds to the baseline. No appeals client code is added here.Not done here
verboseonlist_sled_opportunities(): the API reads it off the request rather than its filter set, so it is absent from the contract and the conformance check would flag it as a stale param. It also only matters when no shape is sent.Opportunityschema, the SDK acceptsdoc_rolethroughvehicles(opportunity(attachments(...))), which the API rejects. That was already true ofextracted_text.Verification
tests/test_opportunity_attachments.py(shape validation plus list and detail round-trips for opportunities and notices) and additions totests/test_sled.py(the two SLED fields validate,delisted_atis in the default list shape and parses to adatetime, detail fields keep the API's types).main's code, 10 of the new tests fail. With only the generator fix reverted, the 4 opportunity tests fail. With only the SLED observations reverted, the type test fails.ruff format --check tango/,ruff check, and strictmypy tango/are clean. Filter/shape conformance: 0 errors. Shape coverage: 0 new gaps.🤖 Generated with Claude Code