An API can add a field without breaking a JSON parser and still expose a wrong application assumption. A Rails adapter that treats every product limit as US dollars may accept an amount against euro limits. Another adapter may keep sending yesterday’s product IDs even though the requested selection means today’s catalog.
Two Tremendous documentation changes make those assumptions concrete. Its product changelog says each SKU now includes currency_code, identifying the currency of that SKU’s minimum and maximum. Its campaign changelog describes ALL_FEE_FREE as a selection expanded when the API call occurs. These were existing documented changes when checked on 20 September 2026, not predicted releases. Currency change, catalog selection change
Carry the unit with the limit
The local experiment uses a synthetic SKU with euro limits of 10.25 through 100.00. Its unsafe adapter compares the numbers but assumes the local currency is USD. It accepts a USD amount of 20. That is the reproduced defect: a consumer’s default replaced information available in the response.
The corrected adapter stores the SKU’s currency alongside its limits in Active Record. Eligibility requires matching currencies and an amount inside the inclusive range. The same USD request is rejected, while EUR 20 is accepted. Separate checks accept 10.25 and 100.00 and reject 10.24 and 100.01.
The fixture defines its amount strings as major currency units and uses BigDecimal for the comparison. That is an explicit local contract, not a claim about the units of every Tremendous endpoint. Before connecting an adapter, verify the specific endpoint’s amount representation and rounding requirements. Neither a currency code nor a successful decimal comparison establishes an exchange rate. This example performs no currency conversion.
Be deliberate about old and new fields
An extra descriptive property and an extra SKU flag do not prevent the corrected import. Missing currency_code, invalid numeric values and reversed limits do. A failed replacement leaves the previously imported SKU data available.
This is a chosen consumer policy for a complete product snapshot. Some applications should retain a record as unavailable until its contract is resolved instead. What matters is that the application does not silently attach its default currency to an unknown amount. The provider’s additive field is not inherently a breaking change; the test exposes the particular interpretation that was wrong.
The product-list reference separately documents currency filtering. A request filter and the units on a returned SKU serve different purposes. Keeping both assumptions explicit makes a saved fixture more useful than checking only that the response has an array of products.
Test who expands the catalog rule
Tremendous documents ALL_FEE_FREE on campaign create/update requests as expanding to concrete product IDs at call time. Products launched later are not automatically included by that selection alone. Its documentation identifies auto_add_product_rule for automatically adding new fee-free gift cards, and says the special selection value is not returned on read. Explicit product IDs may accompany the selection. Campaign behavior
The second negative control caches one fee-free product locally. A second becomes available before campaign creation, but the unsafe adapter sends only its cached ID. The local fake partner therefore creates a campaign missing the new product.
The corrected adapter sends the selection rule, then records the resolved IDs returned by a separate read. The test obtains both currently available products. After another product is added, reading the existing campaign still returns its original selection. Calling the update again expands the rule against the new catalog. Another test includes an explicit product with a fee and verifies that its ID is retained.
| Assumption under test | Result in the local experiment |
|---|---|
| Numeric limits always use USD | Unsafe control accepts a mismatched currency |
| Unknown optional fields must break import | Corrected importer accepts the added fields |
| A cached free-product list equals current selection | Unsafe control misses a newly available product |
| A selection rule stays dynamic after creation | Existing campaign remains unchanged until updated |
Keep the proof smaller than the promise
Six tests passed with 31 assertions using Ruby 3.3.3, Active Record 8.1.3.1 and a temporary SQLite database. AI assistance was used to prepare and execute the fixture. Its partner is entirely local. No Tremendous account, API request, payout or customer data was involved.
The fake implements only the catalog behavior described above. It does not implement automatic-add rules, provider authentication, pagination, caching headers or recovery after a remote write and failed local save. These results do not establish production interoperability or financial correctness.
Use the fixture and evidence record to choose the cases your own adapter needs. For a contained integration change, Allerin’s Rails practice can start the discussion from the interface, the failing assumption and the acceptance check that should replace it.
Download the experiment
Download the runnable Rails examples and evidence summary (ZIP, 36 KB). This article’s example is in q06/; the shared setup and reproduction instructions are in README.md. The package contains eight synthetic examples, checked on 20 September 2026. The recorded runtime, provider fakes and limits are documented inside.