Model firmware-dependent capability limits (option A) - #15
Merged
Conversation
Some radio limits change across firmware versions on the same hardware, and
nothing modelled that. capabilities.json was keyed only on radio id, so one
flat limit set covered every firmware. The instance registry already records
a `firmware` string per physical radio (instance-registry-0.1.schema.json)
and validation never read it.
Known case, DM-32UV ROW line: DM32.01.L01.048 removed the record function and
raised CSV contacts to 150,000; DM32.01.01.049 restored record and returned to
50,000. That is a 3x swing in a hard limit across one version bump, and 048 ->
049 is our actual upgrade path for the green/white pair.
Adds an optional `firmware_limits` block to capabilities 0.2: a map of firmware
version string -> partial limit overrides, reusing the `limits` property set via
$defs/firmwareLimitOverrides so a typo'd or unknown key is still rejected
(limits keeps additionalProperties: false).
Resolution in _resolve_firmware_limits():
- firmware declared in firmware_limits -> base limits updated by that entry
- firmware unknown or absent -> the MINIMUM of the base value and every
declared override, so an uncharacterised radio cannot validate against a
capacity no shipped firmware provides
- radio with no firmware_limits -> unchanged behaviour
The conservative floor is the point of the design: silently assuming the larger
048 ceiling for a radio nobody has identified is how a profile validates clean
and then overflows on hardware.
Limit violation messages now cite the basis ("limit for firmware X" /
"conservative limit across all known firmware") instead of a bare
"radio limit", so an unexpected rejection is self-explaining.
DM-32 capabilities.json declares both firmware entries and sets base
max_contacts to the smaller 50,000. Note that max_contacts still has no
enforcement site -- profile 0.1 carries no contact list to count -- so this
commit makes the limit *correct and firmware-aware*, not yet enforced.
Refs #3.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #3. Does not close it — this covers only the firmware axis, not the rest of the constraint block proposed there.
Problem
capabilities.jsonis keyed on radioidalone: one flat limit set per radio, no firmware axis. Meanwhileinstance-registry-0.1.schema.jsonalready records afirmwarestring per physical radio, and validation never read it.grep -i firmware src/ schemas/ radios/returned exactly one hit before this change — that unused field.Known case, DM-32UV ROW line:
DM32.01.L01.048— record function removed, CSV contacts 150,000DM32.01.01.049— record restored, contacts back to 50,000A 3× swing in a hard limit across one version bump on the same hardware, and 048 → 049 is the real upgrade path for the green/white pair. A profile sized for 048 would validate clean against a 049 radio.
Design
Optional
firmware_limitsin capabilities 0.2 — firmware version string → partial limit overrides. Override objects reuse thelimitsproperty set via$defs/firmwareLimitOverrides, soadditionalProperties: falsestill catches a typo'd key inside an override, andminProperties: 1rejects empty entries. Both verified in the test run below._resolve_firmware_limits():firmware_limitslimitsupdated by that entryfirmware_limitsThe conservative floor is the whole point. Assuming the larger 048 ceiling for a radio nobody has identified is precisely how a profile validates clean and then overflows on hardware. An uncharacterised radio gets the floor across all known firmware, not the optimistic base.
Violation messages now cite their basis —
limit for firmware DM32.01.01.049, orconservative limit across all known firmware (no firmware declared)— instead of a bareradio limit, so an unexpected rejection explains itself.max_contactsis now correct and firmware-aware, but still not enforced anywhere. Profile0.1carries no contact list, so there is nothing to count against it. This commit fixes the data; the check needs a profile-schema change to have anything to check.So the 048/049 case that motivated the work is not yet caught at validation time. What is caught end-to-end is any firmware-varying limit that profile 0.1 does express —
test_instance_firmware_drives_enforcement_end_to_endproves the registry'sfirmwarefield reaches the limit check by using a fixture firmware that lowersmax_channels. The plumbing is real and tested; the contact-specific enforcement is blocked on profile 0.2.I'd rather land the mechanism with an honest gap than imply the overflow is now impossible.
Tests
uv run pytest -q→ 30 passed (was 24).max_channelsbelow basefirmware_limitsis treated as unknown, and says sofirmware_limitsis byte-identical in behaviourfirmwarereaches enforcement end-to-endmax_contactsequals the minimum across themSchema self-validates; all three
radios/*/capabilities.jsonstill pass; unknown-key and empty-override cases both correctly rejected.Not covered
DM32.00.*) has no 049 at all, andDM32.NRF.*is uncharacterised for contacts. Neither is declared — both fall to the conservative floor, which is the safe default. Noted in the radio file'snotes.hardware_familyis also in the instance registry. Limits really vary on family × firmware; this models firmware only. Worth a follow-up if HRV limits ever get characterised.