Twilio dropped subresource_uris from SIP mappings: 6 fixable removals next to 6 that no codemod can touch
What changed
Between twilio-oai 1.10.0 and 1.20.0, the Twilio 2010-04-01 API spec lost 12 response properties. Every one of them is the same change kind, response-prop-removed, and every one is genuinely breaking. Yet half are mendable by machine and half are not, and the split does not follow the change kind at all. It follows what the removed data actually was.
Six removals hit the SIP domain mapping resources. The subresource_uris map is gone from all four read shapes and both create shapes:
GET /2010-04-01/Accounts/{AccountSid}/SIP/Domains/{DomainSid}/CredentialListMappings.json, fieldcredential_list_mappings[].subresource_uris(change 4128)GET .../CredentialListMappings/{Sid}.json, fieldsubresource_uris(4129)GET .../IpAccessControlListMappings.json, fieldip_access_control_list_mappings[].subresource_uris(4130)GET .../IpAccessControlListMappings/{Sid}.json, fieldsubresource_uris(4131)POST .../CredentialListMappings.json201, fieldsubresource_uris(4135)POST .../IpAccessControlListMappings.json201, fieldsubresource_uris(4136)
The other six hit call feedback summaries. The issues[] array stopped being a list of typed objects and became a flat list of issue labels, taking three fields with it on each of two endpoints:
GET /2010-04-01/Accounts/{AccountSid}/Calls/FeedbackSummary/{Sid}.json:issues[].count,issues[].description,issues[].percentage_of_total_calls(4125, 4126, 4127)POST /2010-04-01/Accounts/{AccountSid}/Calls/FeedbackSummary.json201: the same three (4132, 4133, 4134)
The whole 1.10.0 to 1.20.0 corridor holds 25 records: 12 breaking, 13 additive. The adjudication on the breaking dozen splits exactly 6 code-fixable, 6 not-code-fixable.
Who is affected
The two groups fail differently, and that difference is the whole point.
SIP mapping readers lose a convenience, not information. Code that followed mapping.subresource_uris.credential_lists to reach the underlying credential list now reads undefined and concatenates it into a URL. The request goes out malformed rather than throwing at the read site, which is the worst kind of failure to trace back. But nothing was actually lost. The mapping resource still returns the child SID, and 2010-04-01 URLs are a deterministic function of account SID plus resource SID. The spec confirms the compensation directly: the same diff adds domain_sid to all six mapping shapes (changes 4139 through 4142, plus 4148 and 4149). Twilio removed a precomputed link and left every input needed to compute it.
FeedbackSummary readers lose the data itself. A line like summary.issues.sort((a, b) => b.count - a.count)[0] now sorts strings by an undefined property. No later version of the spec exposes per-issue aggregate counts on any endpoint. There is no successor field, no alternate resource, no query parameter that brings the numbers back.
That asymmetry is why change kind is a useless triage signal on its own. Both groups are response-prop-removed. Both are breaking. One is a mechanical URL construction. The other is a product decision about whether to build your own aggregation pipeline or drop the metric.
How to fix it
Scanning tells you which of the two you are actually in, with file and line, and without your code leaving the machine:
npx mendapi scan --repo .
For the six SIP removals the adjudicated strategy is replace-uri-read-with-local-construction, at high confidence, with the spec evidence recorded alongside the verdict: subresource_uris appears 23 times in the cached 1.10.0 spec and 21 times at 1.20.0, absent from the mapping schema, while the child resources stay addressable at their conventional paths in every later version. The shape of the edit:
// before
const listUrl = mapping.subresource_uris.credential_lists;
const list = await fetchJson(`https://api.twilio.com${listUrl}`);
// after
const list = await fetchJson(`https://api.twilio.com/2010-04-01/Accounts/${accountSid}/SIP/CredentialLists/${mapping.sid}.json`);
For the six FeedbackSummary removals the recorded strategy is none-data-discontinued, and mendapi says so in the report rather than drafting a patch that pretends otherwise. The only mechanical help available there is defensive: treat issues entries as strings and delete property access on them. Restoring the metric is your call, not a codemod's.
There is no rule pack for either group. These twelve verdicts come from the adjudication layer, which is why a reason string and spec evidence ship with each record instead of a pack name. With your own LLM key configured, and mendapi never proxies credentials, the adjudication becomes a reviewable draft patch:
npx mendapi llmfix --from-report .mendapi/impact.json
Dry run is the default posture throughout: you review a diff, your working tree stays untouched. The Twilio tracker page carries all 12 verdicts with their evidence, and the Twilio parity capstone documents how this corridor was measured against oasdiff across 20 consecutive spec pairs.
Related
- twilio breaking-change guide — every tracked twilio entry on one page, with fixability verdicts.
- 20 Twilio spec pairs: 358 findings from one engine, 142 from ours, and every disagreement named — the long-form methodology report behind this provider's tracked changes.
- All monitored providers — live change counts for twilio and 19 others.
- Migration pack catalog — every deterministic fix mendapi ships.
- Getting started — scan your repo in 30 seconds, no code leaves your machine.