A device page that shows only version = 2.7.4 looks reassuring. It becomes almost useless when the device is online but its data is interpreted incorrectly. Which binary is executing? Which endpoint, threshold, and feature flags were activated? Which capability model is the platform using to decode telemetry and validate commands? Those answers can come from three releases owned by three different teams.
The practical conclusion is simple: compressing firmware, runtime configuration, and the device model into one version number disguises independent changes as one upgrade. As hardware revisions, fleet size, and integration paths grow, diagnosis, compatibility decisions, and rollback become ambiguous. A safer design keeps a version vector and admits each combination through an explicit compatibility contract.
Here, a device model is not a marketing product name. It is the executable semantic contract used by the platform: property types, units, access modes, enums, command parameters, raw-point mappings, and migration rules. Firmware determines what a device can execute. Configuration determines how this device operates now. The device model determines how the platform interprets and controls it. They are related, but none is a substitute for another.
1. Govern a vector of facts, not one decorative version
An operable device record normally needs at least hardware_revision + firmware_version + config_version + model_version. Hardware changes slowly but constrains executable firmware. Firmware carries drivers, protocol stacks, and control logic. Configuration carries site parameters, sampling intervals, endpoints, secret references, and feature flags. The model defines platform-side meaning and command boundaries. A UI may display them on one line, but the underlying facts must remain independent.
A single version forces one of two bad patterns. Some teams issue a new firmware release whenever a threshold changes. The binary is identical, yet the release history fills with “firmware” events and reviewers cannot distinguish code risk from parameter risk. Other teams overwrite configuration or a model silently. The displayed firmware remains unchanged even though state interpretation or command constraints have changed. The first pattern creates noise; the second hides risk.
The lifecycles are also different. Firmware needs a build, signature, integrity check, hardware admission, installation, and boot-health signal. Configuration needs schema validation, scope resolution, secret validation, and atomic activation. A device model needs mapping health, compatibility classification, migration evidence, and platform publication. Forcing all three through the heaviest lifecycle makes small changes unnecessarily expensive. Giving them one loose display label provides no enforcement at all.
A unified release number can still be useful as the name of a release manifest. For example, a manifest may recommend firmware 2.7.4 + config 18 + model 6. It must not erase the component versions or imply that this is the only legal state. A real fleet always contains installing, offline, rolled-back, and partially migrated devices with several valid combinations.
The decision flow therefore starts with ownership of the change, not with a debate over whether the next label should be 2.8.0 or 2.7.5.
flowchart TD
A("A change is requested"):::slate --> B{"Does execution code change?"}:::blue
B -->|Yes| C("Create firmware version"):::blue
B -->|No| D{"Do runtime parameters change?"}:::cyan
D -->|Yes| E("Create config version"):::cyan
D -->|No| F("Create device-model version"):::violet
C --> G("Build compatibility claim"):::orange
E --> G
F --> G
G --> H{"Does target combination pass admission?"}:::orange
H -->|Pass| I("Bind and activate"):::green
H -->|Reject| J("Keep previous combination and record blocker"):::slate
classDef blue fill:#EAF4FF,stroke:#3B82F6,color:#16324F,stroke-width:2px;
classDef cyan fill:#E9FBF8,stroke:#14B8A6,color:#134E4A,stroke-width:2px;
classDef orange fill:#FFF3E8,stroke:#F08A24,color:#7C3F00,stroke-width:2px;
classDef violet fill:#F4EDFF,stroke:#8B5CF6,color:#4C1D95,stroke-width:2px;
classDef green fill:#ECFDF3,stroke:#22C55E,color:#14532D,stroke-width:2px;
classDef slate fill:#F8FAFC,stroke:#64748B,color:#1F2937,stroke-width:2px;
2. Decide who interprets whom before incrementing a version
The most common ambiguity sits between configuration and the device model. Changing a temperature limit from 80 to 75 is a configuration change. Changing the temperature property from integer Celsius to one-decimal Fahrenheit is a model change. Replacing a moving-average filter with a Kalman filter is usually a firmware change. The decision is not based on which file was edited. It is based on whether the change affects execution logic, operating parameters, or the data-and-command contract.
| Change | Primary axis | Reason | Typical verification |
|---|---|---|---|
| Driver, protocol stack, or control algorithm | firmware | Changes executable device code | signature, hardware match, install and boot health |
| Sampling interval, endpoint, threshold, or feature flag | config | Changes operation within existing capability | schema, scope, secret reference, atomic activation |
| Property type, unit, enum, command parameter, or raw mapping | model | Changes platform interpretation or control contract | mapping health, write safety, migration evidence |
| PCB, sensor, flash, or radio replacement | hardware | Changes firmware prerequisites | BOM revision, bootloader and driver compatibility |
The table establishes a primary ownership axis, not a rule that every change touches only one axis. A new sampling mode may require firmware support, a configuration switch, and a model property. The correct response is to increment every affected component and declare their dependencies in a manifest. Multiple explicit versions are manageable. Hidden cross-component dependencies are not.
Each axis also needs an accountable owner. The firmware owner is responsible for binary provenance, signing, supported hardware, and boot health. The configuration owner is responsible for schema, defaults, scope, and secret references. The model owner is responsible for meaning, mappings, command safety, and compatibility classification. One engineer may hold several roles, but the audit event should still show which role approved which change.
The current Grus implementation provides a concrete example. A released device-model version cannot mutate its description, diff, compatibility class, baseline, or migration evidence; a change requires a new version. A device may bind only to a released model with matching product and source identity. This does not prove that every platform should copy the implementation, but it demonstrates how release immutability and explicit binding turn a drifting JSON document into a traceable runtime fact.
3. Compatibility is an admission contract, not a boolean label
Teams often store backward_compatible: true without saying compatible with whom, based on which checks, or until when. That boolean provides little help during an incident. A useful compatibility record identifies producer, consumer, supported range, required migration, and validation evidence so that the system can reject an unsafe combination.
For firmware, the consumer is usually a hardware revision and bootloader. For configuration, it is the configuration schema embedded in firmware. For a device model, consumers include ingest normalization, state storage, command validation, and rule evaluation. A model may remain read-compatible with old telemetry while no longer being write-compatible with old firmware. Separating read and write compatibility is usually more honest than one global flag.
A practical admission record can include artifact identity, supported hardware revisions, required firmware range, configuration schema version, model compatibility class, migration identifier, evidence digest, approver, and expiry. It does not need a general-purpose policy language on day one. It does need to answer why a particular device is allowed to run a particular combination.
The Grus model release checklist treats an empty mapping catalog for affected devices, mapping conflicts, blocked mappings, and missing schemas as release blockers. Unknown or provisional mappings and unmapped raw data are degraded conditions that require a waiver with a reason and expiry. The important decision is not the field naming. It is the refusal to interpret “not validated” as “compatible.” Once affected devices exist, an empty mapping is not documentation debt; it removes the platform's ability to interpret or control them safely.

Admission must also bind observed state, not only release-catalog intent. The platform should store the firmware reported by the device, the last configuration acknowledged as active, the effective model version, the hardware revision, and freshness timestamps. An offline device may receive a desired plan, but the platform should not claim that the combination is effective until it has evidence. Desired state expresses intent; reported and effective state express reality.
Cross-vendor integrations add another identity trap. The same product key is not necessarily a global identity. A model version should be scoped by tenant, source platform, and product identity. If the source changes or a product key is reused, compatibility must be evaluated again. Otherwise a mapping proven for vendor A may silently be applied to an unrelated device from vendor B.
4. Firmware, configuration, and model rollback are different operations
Firmware rollback can switch a partition, restore an image, or reflash a device. A bootloader, anti-rollback counter, and persistent-data migration may constrain it. Configuration rollback reactivates a schema-valid snapshot, but its endpoint, certificate, or secret reference may have expired. Model rollback changes how the platform interprets data and commands; it does not rewrite already stored data or undo the physical effect of commands sent under the newer model.
“Keep the previous version” is therefore not a production rollback plan. Every rollback record must identify the reversible object and irreversible side effects. If a device data format was migrated irreversibly, old firmware may no longer boot correctly. If an old configuration refers to revoked credentials, restoring the JSON creates a fresh outage. If model rollback removes a conversion or enum mapping, historical charts can change meaning even when their stored values do not change.
Each axis needs its own retirement rule. Firmware may retire after target hardware has remained healthy and the recovery window has closed. Configuration may retire after every scope has converged, old secrets are replaced, and offline-device handling is explicit. A model may retire after bound devices migrate, read/write compatibility windows close, and historical interpretation is settled. Retirement means that the system has evidence it no longer needs that version for recovery or interpretation, not merely that nobody selected it recently.
When a release changes all three axes, activate them in an observable dependency order rather than flipping them simultaneously. One common path publishes a backward-compatible model first so the platform can read old and new data, releases firmware that supports both schemas second, activates configuration third, and retires old model/config states only after migration evidence is complete. The exact order follows dependency direction, but the rule is stable: teach consumers both states before producers begin emitting only the new state.
This distinction separates version governance from OTA rollout. Canary cohorts, pause conditions, and recovery control how an admitted artifact reaches the fleet. Version governance decides whether the artifact remains legal when combined with configuration, model, and hardware. Without rollout control, blast radius is uncontrolled. Without compatibility governance, the team merely deploys an invalid combination more carefully. For the delivery mechanics, see Why IoT OTA Must Support Canary Rollouts and Rollbacks.
5. Start with the minimum mechanism, but preserve traceability
A small team does not need a large “version governance platform.” With one hardware revision, one firmware branch, and a few static settings, a signed manifest, a compatibility table, and device-reported state can establish basic control. The initial implementation may be relational tables and a release gate rather than a universal rule engine.
Four controls are still non-negotiable. Every artifact needs content identity or at least an immutable digest, so one version cannot point to different bytes. A released version record must not be edited silently; corrections require a new version or an explicit revocation. Devices must report effective versions and acknowledgement times, because desired state is not proof of activation. Every bind, waiver, rollback, and retirement event needs an operator, reason, evidence, and trace identifier.
There is also a boundary where the overhead is not justified. A fully offline, short-lived, single-purpose device with no remote configuration and no platform-side semantic mapping may need only a build identifier, factory configuration checksum, and hardware revision. In contrast, when a system has any two of multiple hardware revisions, remote configuration, third-party integration, writable commands, or long-lived historical data, compressing versions into one string postpones cost into incident response and migration.
The target is not “every device runs the latest version.” It is “every device runs a provably legal combination.” The latest firmware may be invalid for an older hardware revision, while an older approved combination may remain compliant during a support window. Useful metrics are therefore unknown combinations, blocked combinations, expired evidence, devices in migration, and irreversible changes—not only latest-version adoption.
Once an operator can trace any device to hardware, firmware, configuration, model, compatibility evidence, and approvals, version identifiers become operational tools. Before that, they are labels that make the interface look more certain than the system really is.
References
Conclusion
Version firmware, configuration, and the device model independently, then combine them through a manifest and compatibility contract. Classify each change onto the correct axis, admit combinations only with evidence, and manage rollback and retirement according to their different irreversible effects. The approach adds some metadata and review work, but it produces device states that can be diagnosed, rejected, migrated, and audited.
