Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,27 @@ All notable changes to the `makegov-tango` and `makegov-tango-webhooks` crates a

This project follows [Semantic Versioning](https://semver.org/).

## [Unreleased]

### `makegov-tango`

#### Added

- **`attachments(extracted_text)` — SLED document bodies on the Small plan and above** (Tango API 4.25.1; parity with tango-python, tango-node and tango-go). This SDK returns `Record`, so the leaf needs no type change — what it needed was saying so. Documented on `get_sled_opportunity`, on `SHAPE_SLED_OPPORTUNITIES_COMPREHENSIVE` and in `docs/API_REFERENCE.md`: the leaf must be **named** (no `SHAPE_SLED_*` constant includes it, and `attachments(*)` does not carry it, because the API resolves the body only for a caller who asked); the **key is absent rather than null** when the text is not being served; and a **contested document never returns text at any plan**. `suggested_shapes_do_not_name_the_paid_document_body` pins the constants. Searching document text stays ungated on every plan and returns no fragment of it.

- **State, local and education (SLED) procurement** (Tango API 4.25.0; parity with tango-python, tango-node and tango-go). `resources/sled.rs` adds `list_sled_opportunities` / `get_sled_opportunity`, `list_sled_opportunity_revisions`, `get_sled_coverage`, `list_sled_forecasts` / `get_sled_forecast`, plus `iterate_sled_opportunities` and `iterate_sled_forecasts`. Four `bon`-derived options builders (`ListSledOpportunitiesOptions`, `ListSledOpportunityRevisionsOptions`, `ListSledForecastsOptions`, `GetSledOptions`) name every one of the API's 27 solicitation filters and 13 forecast filters, and five `SHAPE_SLED_*` constants land in `shapes.rs`.

Four behaviors are documented on the options builders because each misleads a caller who assumes federal semantics. **Leaving both `status` and `active` unset returns open solicitations only** — that default is the API's, and `list_sled_opportunities` deliberately does not synthesize `status=open`, since doing so would make `active = Some(false)` unreachable (pinned by a test). **`status` is Tango-derived and refreshed every fifteen minutes**; the portal's own word is served as `source_status`, is frozen at last capture, and is not a liveness filter. **Category scheme tagging is mid-migration**, so `naics` matches only the small tagged share and `category_code` is the escape hatch. And **`meta.attachment_count` can be lower than the length of `attachments`**, because an auto-generated portal cover sheet is listed and flagged `is_generated_summary` but excluded from the count.

`active`, `has_documents` and `source_declared` are `Option<bool>` rather than `bool`, so `false` reaches the server as a filter value instead of collapsing into the default — the same reason `push_opt_bool` exists.

`SHAPE_SLED_REVISIONS_MINIMAL` omits `changes` on purpose: the per-field before/after needs a Small plan, so naming it in a suggested shape would 403 a Free caller. `changed_fields` is in the shape and available at every plan.

#### Documentation

- New **State & Local — SLED** section in `docs/API_REFERENCE.md` covering all six methods and both defaults that surprise people.
- `docs/WEBHOOKS.md` alert semantics gained the date-lapse rule and its one exception. An exclusion or DIBBS solicitation reaching its date fires nothing, because open/closed is derived at query time — but `alerts.sled_opportunity.match` **does** fire on a closing, since SLED liveness is a stored column a fifteen-minute sweep writes.

## [0.1.0] — 2026-05-15

First public release of the Tango Rust SDK.
Expand Down
8 changes: 5 additions & 3 deletions crates/tango/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,11 @@ pub use shapes::{
SHAPE_GSA_ELIBRARY_CONTRACTS_MINIMAL, SHAPE_IDVS_COMPREHENSIVE, SHAPE_IDVS_MINIMAL,
SHAPE_ITDASHBOARD_INVESTMENTS_COMPREHENSIVE, SHAPE_ITDASHBOARD_INVESTMENTS_MINIMAL,
SHAPE_NOTICES_MINIMAL, SHAPE_OPPORTUNITIES_MINIMAL, SHAPE_ORGANIZATIONS_MINIMAL,
SHAPE_OTAS_MINIMAL, SHAPE_OTIDVS_MINIMAL, SHAPE_PROTESTS_MINIMAL, SHAPE_SUBAWARDS_MINIMAL,
SHAPE_VEHICLES_COMPREHENSIVE, SHAPE_VEHICLES_MINIMAL, SHAPE_VEHICLE_AWARDEES_MINIMAL,
SHAPE_VEHICLE_ORDERS_MINIMAL,
SHAPE_OTAS_MINIMAL, SHAPE_OTIDVS_MINIMAL, SHAPE_PROTESTS_MINIMAL,
SHAPE_SLED_FORECASTS_COMPREHENSIVE, SHAPE_SLED_FORECASTS_MINIMAL,
SHAPE_SLED_OPPORTUNITIES_COMPREHENSIVE, SHAPE_SLED_OPPORTUNITIES_MINIMAL,
SHAPE_SLED_REVISIONS_MINIMAL, SHAPE_SUBAWARDS_MINIMAL, SHAPE_VEHICLES_COMPREHENSIVE,
SHAPE_VEHICLES_MINIMAL, SHAPE_VEHICLE_AWARDEES_MINIMAL, SHAPE_VEHICLE_ORDERS_MINIMAL,
};
pub use transport::RateLimitInfo;
pub use version::VERSION;
Expand Down
5 changes: 5 additions & 0 deletions crates/tango/src/resources/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub(crate) mod opportunities;
pub(crate) mod otas;
pub(crate) mod protests;
pub(crate) mod resolve_validate;
pub(crate) mod sled;
pub(crate) mod subawards;
pub(crate) mod vehicle_subresources;
pub(crate) mod vehicles;
Expand Down Expand Up @@ -51,6 +52,10 @@ pub use otas::{
GetOTAOptions, GetOTIDVOptions, ListOTAsOptions, ListOTIDVAwardsOptions, ListOTIDVsOptions,
};
pub use protests::{GetProtestOptions, ListProtestsOptions};
pub use sled::{
GetSledOptions, ListSledForecastsOptions, ListSledOpportunitiesOptions,
ListSledOpportunityRevisionsOptions,
};
pub use subawards::ListSubawardsOptions;
pub use vehicle_subresources::{ListVehicleAwardeesOptions, ListVehicleOrdersOptions};
pub use vehicles::{GetVehicleOptions, ListVehiclesOptions};
Expand Down
Loading
Loading