Task · MDE-0065

Omit absent network filters from organization MS port requests

Description

The post-v2 live soak confirmed a default-path API accounting and fallback defect. OrganizationInventory.get_allowed_network_ids() returns None when filtering is inactive (src/meraki_dashboard_exporter/services/inventory.py:187-218), but both organization-wide MS port paths always pass that value as networkIds (src/meraki_dashboard_exporter/collectors/devices/ms.py:926-939 and 1491-1505). The installed SDK serializes the keyword and the live API rejects it as an invalid network ID, so each due cycle spends failed calls and falls back to per-device collection even though no filter was requested. During an observed healthy soak, the manager still reported successful DeviceCollector cycles while its api_client_error series rose from 1 to 6. tests/unit/collectors/test_ms_collector.py:41 configures the inactive-filter result but its mocks accept arbitrary keywords and no test asserts that the absent filter is omitted. This is a live medium-severity defect: collection recovers, but the preferred bulk path is unusable, API budget is wasted, and health hides the repeated endpoint failure.

Acceptance Criteria

Definition of Done

Implementation Notes

2026-09-04 main thread. Failing-first evidence: the two omit-keyword regressions failed with networkIds present and set to None, while the non-empty-filter and empty-filter regressions passed unchanged, confirming the defect is specific to the inactive-filter case.

The audit found a THIRD call site the task description did not name: getOrganizationSwitchPortsClientsOverviewByDevice inside collect_port_usage_by_switch shared the same network_ids variable and therefore the same defect. All three now build a filter_kwargs mapping that is empty when get_allowed_network_ids returns None and carries sorted IDs otherwise, so the keyword is omitted rather than serialized as null. The zero-match short circuit is untouched.

Focused result after the fix: 49 passed for the whole MS collector module, including the two collateral usage-path tests that broke mid-change. Full gate: just check 2945 passed, 5 deselected, 91.49% coverage. CodeRabbit reported 0 findings across both changed files.

Final Summary

Fixed in 84aa7e8. All three organization-wide MS port call sites (statuses-by-switch, usage-history-by-device, and the previously unnamed clients-overview-by-device) now omit networkIds entirely when no filter is configured, instead of serializing an explicit null the API rejects. Non-empty filters are still passed sorted and a zero-resolving filter still short circuits. Verified by five focused regressions, two of which were watched failing with the keyword present and None; MS module 49 passed; just check 2945 passed at 91.49% coverage; CodeRabbit 0 findings. DoD2: just check’s generated-drift gate passed with no metric, config, endpoint or schema change. DoD3: no metric or label name moved, so no Grafana query needed updating.

View the source file on GitHub