#Why devices make versioning hard
AddedOn a web service, you deploy the server and within minutes every client is talking to the new version. The only old code left is in the clients, and the System Design course's API versioning topic is mostly about them: mobile apps that stay installed for years, partner scripts nobody maintains. On a device platform the relationship flips. The API server is the device. Every video bar, phone and touch controller runs its own copy of the API, at whatever firmware it last installed, and it may stay on that firmware for years. Your API isn't one version; it's every version you ever shipped that's still plugged in somewhere.
So the problem runs in both directions at once. An old client meets new firmware when a control-system integration written in 2021 talks to a device that updated last night: the device must keep behaving the way the old client expects. A new client meets old firmware when this year's cloud manager or admin dashboard talks to a device that hasn't updated since 2023: the client must notice what the device can't do and degrade politely instead of failing. A web service only has the first problem. A fleet has both, for every pair of client and firmware version that exists in the field.
A good mental model: a fleet is a museum of your releases. Each device is an exhibit, frozen at the release it last installed. Visitors of every age (scripts, integrations, dashboards, the vendor's own cloud) walk through every room, and none of them can repaint an exhibit. Versioning on devices is the job of making every visitor's tour work in every room, or end at a clear sign rather than a crash.
Why old firmware lingers for so long, even when updates are free and automatic:
- Hardware that can't run the new line. A new OS base (a newer Android, for example) needs more memory, a newer chipset or vendor drivers that older models don't get.
- Customers who pin versions. Enterprises run change control: an update is tested in one room, approved, then rolled out on their schedule. Some wait for a partner's certification first.
- Devices that are rarely online or sit on networks that can't reach the update server, in a cupboard, a closed office, a secure site.
- One-way upgrades make administrators careful: if they can't roll back, they wait for others to go first.
- Staged rollouts by the vendor itself: a release reaches 1%, then 10%, then everyone, over weeks.
What public Poly documents show
The role you're preparing for works on exactly this kind of fleet. These are public facts, checked in October 2026:
- A one-way major release on newer hardware only. HP's official Poly VideoOS Software Release Notes 5.X (HP Support, 5.0.0 released May 2026, read 27 October 2026) say that "only Poly Studio G62, Poly Studio X32, Poly Studio X52, and Poly Studio X72 systems support Poly VideoOS 5.0.0" and that "once you update your system to Poly VideoOS 5.0.0, you cannot downgrade". A post announcing the release in the Poly Video Conferencing Knowledge Base on the HP Support Community (6 May 2026; the site states that posts are their authors' opinions, not HP's) names the Poly Studio X30, X50, X70, G7500 and the TC8 controller as incompatible. Devices must be on 4.6.0 or later first; older ones install 4.6.0 automatically on the way (release notes). The Poly VideoOS 5.0 Compatibility Reference Guide (HP, March 2026) repeats that systems on 5.0 cannot be downgraded to 4.x, and warns not to upgrade if your conferencing provider isn't on its list (5.0 lists Microsoft Teams Rooms and Poly Device Mode).
- Two release lines at once. A month later, Poly VideoOS 4.7.0 (June 2026) shipped "for all providers", according to its post in the same HP Support Community knowledge base (18 June 2026). The post's title names the newer G62, X32, X52 and X72, and its fixes also mention the G7500 and the Studio X30, X50 and X70. So the 4.x and 5.x lines were both being released in mid-2026, and the older models stay on 4.x.
- An OS jump underneath. The 5.0.0 release notes describe the platform update on those four models as "from Android 10 to Android 13" (the TC10 touch controller goes from Android 11 to 12). The role description you have talks about Android 11 to 13; the public release notes and the job description differ, so ask which devices they mean.
- Partner certification gates updates. The 4.7.0 post notes that Microsoft hadn't yet added the release to the Teams Admin Center, so Poly officially didn't recommend updating yet.
The public documents don't say how long the 4.x line will be maintained, or how many devices are on each version. The point stands without those numbers: anyone integrating with these devices' APIs must expect at least two firmware lines, and some hardware that will never leave the older one.
How long the tail is
This seeded model runs a fictional fleet of 10,000 video bars for a year. 40% are Gen 1 hardware that can't run 8.x; most devices update automatically, some customers pin versions, and a few devices are rarely online. Release 7.3 ships in week 0 for everyone; 8.0 ships in week 10 for Gen 2 only.
// A seeded model of a device fleet over a year: which firmware versions are still out there?
// 10,000 video bars. Gen 1 hardware can't run 8.x; some customers pin versions; some devices are rarely online.
function mulberry32(a) { // small seeded PRNG, so every run prints the same numbers
return () => { a |= 0; a = (a + 0x6d2b79f5) | 0; let t = Math.imul(a ^ (a >>> 15), 1 | a);
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t; return ((t ^ (t >>> 14)) >>> 0) / 4294967296; };
}
const rand = mulberry32(42);
const VERSIONS = ["7.0", "7.1", "7.2", "7.3", "8.0"];
const pick = (weights) => { let r = rand(), i = 0; while (r > weights[i]) r -= weights[i++]; return i; };
const fleet = Array.from({ length: 10_000 }, () => ({
gen: rand() < 0.4 ? 1 : 2, // 40% older hardware
v: pick([0.1, 0.2, 0.7]), // index into VERSIONS: 7.0, 7.1 or 7.2 today
policy: ["auto", "auto", "auto", "pinned", "offline"][pick([0.2, 0.2, 0.3, 0.2, 0.1])],
}));
// Chance per week that a device on each policy installs the newest release it is offered.
const weekly = { auto: 0.3, pinned: 0.03, offline: 0.005 };
function newestFor(device, week) {
if (week >= 10 && device.gen === 2) return 4; // 8.0 ships in week 10, Gen 2 only
return 3; // 7.3 ships in week 0 for everyone
}
function report(week) {
const counts = VERSIONS.map((_, i) => fleet.filter((d) => d.v === i).length);
let covered = 0, oldest = VERSIONS.length; // add versions from the newest down until 99% are covered
while (covered < 9_900) covered += counts[--oldest];
const cells = counts.map((n) => `${(n / 100).toFixed(1)}%`.padStart(7)).join("");
console.log(`week ${String(week).padStart(2)}${cells} 99% needs ${VERSIONS[oldest]}+`);
}
console.log(" " + VERSIONS.map((v) => v.padStart(7)).join("") + " oldest a client must support");
for (let week = 0; week <= 52; week++) {
if ([0, 4, 10, 16, 26, 52].includes(week)) report(week);
for (const d of fleet) {
const target = newestFor(d, week);
if (d.v < target && rand() < weekly[d.policy]) d.v = target;
}
}
const stuck = fleet.filter((d) => d.gen === 1).length;
const on7 = fleet.filter((d) => d.v < 4).length;
console.log(`\nafter a year: ${on7} devices (${on7 / 100}%) still on 7.x, ${stuck} of them Gen 1 hardware that can never run 8.x`); 7.0 7.1 7.2 7.3 8.0 oldest a client must support
week 0 9.9% 20.1% 70.0% 0.0% 0.0% 99% needs 7.0+
week 4 4.4% 8.9% 31.2% 55.4% 0.0% 99% needs 7.0+
week 10 2.6% 4.9% 18.5% 74.0% 0.0% 99% needs 7.0+
week 16 2.1% 4.1% 15.2% 38.5% 40.2% 99% needs 7.0+
week 26 1.6% 3.4% 12.3% 34.5% 48.1% 99% needs 7.0+
week 52 1.1% 2.3% 8.2% 35.6% 52.8% 99% needs 7.0+
after a year: 4706 devices (47.06%) still on 7.x, 3937 of them Gen 1 hardware that can never run 8.x- Week 0: the fleet starts on three versions (roughly 10% on 7.0, 20% on 7.1, 70% on 7.2). Each device is assigned a hardware generation and a policy from a seeded PRNG (mulberry32 with seed 42), so the run is the same every time.
- Each simulated week, every device behind the newest release it's allowed gets a chance to update: 30% for automatic devices, 3% for pinned ones, 0.5% for devices that are rarely online. By week 4, 7.3 already has 55.4% of the fleet: automatic updates work.
- In week 10, 8.0 ships for Gen 2 only. By week 16 it has 40.2% and by week 52, 52.8%. It can't go much higher: 3,937 devices (39.37%) are Gen 1 and will run 7.x for the rest of their lives.
- The right-hand column is the question a client team actually asks: "what's the oldest firmware we must support to reach 99% of devices?" The code adds up shares from the newest version down until it covers 9,900 devices. After a full year, the answer is still 7.0: 1.1% of the fleet never moved (107 devices; counting them by policy gives 76 rarely online and 31 pinned, and no automatic ones). A year of releases didn't shorten the support window at all.
- After the year, 4,706 devices (47.06%) are still on 7.x. A client that only speaks 8.x reaches half the fleet. That's why "just make customers upgrade" isn't an answer, and why the rules in the rest of this chapter matter.
- If you change the Gen 1 share from
0.4to0and run it again, 8.0 reaches 86.4% by week 52, and the 99% answer is still 7.0: the pinned and rarely online devices, not the hardware, set the tail. The numbers are invented; the shape, fast early adoption and then a long tail, is the point.
Who the clients are
It helps to list every client of a device API, because each one ages differently:
| Client | Built when | Updated how | Versioning problem |
|---|---|---|---|
| On-device web UI | with the firmware | with the firmware | almost none, except a browser tab loaded before an update |
| Vendor cloud manager | continuously | the vendor deploys it | must talk to every firmware in the field |
| Partner integrations (room control systems, schedulers) | once, against one firmware | rarely, by someone else | must keep working on every newer firmware |
| Customers' scripts | once | almost never | the same, with no tests and no owner |
| Companion devices (touch controllers, cameras) | their own firmware | their own update cycle | device-to-device compatibility in both directions |
| Provisioning servers and config files | per customer | when an admin edits them | one config pushed to many firmware versions |
The on-device web UI looks like the easy case because it ships with the firmware it talks to. But an administrator's browser tab that loaded the UI before an update is now an old client talking to new firmware after the device reboots. The UI should notice (the firmware version from the API or a response header changes) and reload itself.
Because you can't make old firmware disappear, you decide explicitly what you support, and write it down:
- Clients (the cloud manager, SDKs, the admin dashboard) support a window of firmware, chosen from fleet data, not guessed: "every firmware released in the last three years", or "7.0 and later". The fleet model above is the kind of report that decides it.
- Firmware supports a window of API versions: each release lists the API major versions it serves (more in Versioning strategies: URL, header and media type).
- Below the window, fail clearly. A cloud manager meeting firmware older than it supports should say so ("this device runs 6.4; update to 7.0 or later to manage it here"), not show a half-working page.
- Report versions on the wire. Every device should expose its model, firmware version and supported API versions on a cheap, unauthenticated-or-low-privilege endpoint, so clients and fleet tools can decide before calling anything else.
A room-control integration written in 2021 against firmware 7.0 recalls camera presets. A cloud dashboard released this month shows a new microphone-zones panel that only firmware 8.0 supports. Both are used across a fleet of 7.0, 7.3 and 8.0 devices. For each one, which direction of compatibility is at stake, and who has to do the work?
Show answer
The integration is an old client meeting new firmware: the firmware owes it. The dashboard is a new client meeting old firmware: the dashboard owes it.
- The 2021 integration can't change: nobody will update it. On 7.3 and 8.0 it still sends the 7.0 requests and reads the 7.0 response fields. So every newer firmware must keep those requests working and those fields present with the same meaning. That's backward compatibility, and it's the firmware team's obligation.
- The dashboard is new, and it will meet 7.0 and 7.3 devices that have no microphone zones and never will (no firmware update changes the device it's talking to right now). So the dashboard must find out per device whether zones exist and hide or explain the panel. That's the client's obligation, solved with capability discovery.
- The firmware team can't help the dashboard on old devices (that firmware is already shipped), and the dashboard team can't help the old integration (it's someone else's code). Each obligation lands on the only side that can still change.
- The general rule: whoever ships later carries the burden. New firmware carries old clients; new clients carry old firmware.