Every measurement_id the rXg produces, every protobuf ID the webhook accepts, and the gap between the two.
measurement_id: literal under
console/app/lib/telemetry/{cisco,ruckus} on rgnets/rxg@32c0dfea95
(branch hbh/kpi-update). Protobuf IDs extracted from ATT_PROTOBUF_MEASUREMENT_TYPES in
notifications.yaml on rgnets/att-templates@0e44313f27
(branch hbh/combined-new-schema). The three tables below are set operations over those two lists, so they
are exhaustive as of 2026-09-17 — not a curated selection.| Set | Count | Meaning |
|---|---|---|
| Map entries | 71 | Keys in ATT_PROTOBUF_MEASUREMENT_TYPES (69 distinct ints — two are double-assigned). |
| Delivered | 31 | Produced by a vendor and mapped. This is what AT&T actually receives. |
| Dropped in transit | 12 | Produced by a vendor, absent from the map, silently discarded by the webhook's select. |
| Reserved | 40 | Mapped, but no code emits them. Aspirational or awaiting a producer. |
Accessor columns name the method on Telemetry::Cisco::Grpc::Grpc / Telemetry::Ruckus::Mqtt::Mqtt
that supplies the value, so you can trace any number back to its computation. Radio metrics carry
source_subtype 0 and a band source_subcategory; switch and port metrics carry source_subtype 1.
| ID | measurement_id | Cisco | Ruckus | Backing accessor | Notes |
|---|---|---|---|---|---|
| Radio — phase 1 — source_subtype 0, extra = radio slot ID | |||||
| 111 | client_count_per_ap | Y | Y | client_counts | Distinct client MACs per radio. Ruckus gates the whole client-derived block on this being non-zero. |
| 112 | channel_utilization_avg | Y | Y | channel_utilizations | Ruckus source field is airtime. |
| 113 | throughput_per_client_avg | Y | Y | ap_to_client_throughput_avgs | Downstream only, despite the name. Webhook divides by 10⁶ → Mbps. |
| 114 | aggregate_throughput_avg | Y | Y | ap_to_client_ + client_to_ap_throughput_avgs | Sum of both directions. Webhook divides by 10⁶ → Mbps. |
| 115 | rssi_avg | Y | Y | rssi_avgs | Ruckus reads receiveSignalStrength. See the SNR/RSSI caveat below. |
| 116 | snr_avg | Y | Y | snr_avgs | Ruckus reads client["rssi"] — the vendor's field names are crossed. See caveat. |
| 117 | mcs_avg | Y | Y | mcs_avgs | Derived, not reported: StatsTask::McsComputation back-solves an index from rate + PHY + NSS + width. Computed last because it depends on the others. |
| 122 | noise_avg | Y | Y | noise_floors | Cisco falls back to a second source: noise_floors || noise_floors2. |
| 123 | radio_band_primary_channel | Y | Y | current_channels | |
| 124 | radio_channel_width | Y | Y | channel_width_avgs | An average width is sent, not the configured one. |
| 126 | radio_power_level | Y | Y | tx_powers | Shares 126 with radio_gain — deliberate, commented in the map as "Map radio_gain to RADIO_POWER_LEVEL". |
| 126 | radio_gain | Y | Y | gains | Same int as above. AT&T cannot distinguish the two without measurement_id. |
| Switch — phase 2 — source_subtype 1, switch-level, Cisco only | |||||
| 4000 | switch_version | Y | — | svalue: version | String metric — travels in svalue. |
| 4001 | switch_poe_budget | Y | — | poe_budget | Collides with the reserved temperature key, also 4001. Almost certainly meant 4002. |
| 4003 | switch_poe_usage | Y | — | poe_usage | |
| 4005 | switch_stp_mode | Y | — | stp_mode | e.g. stp-mode-rapid-pvst. |
| 4006 | switch_routes | Y | — | routes | List metric — repeated Route message in the proto. |
| 4007 | switch_vlan_stp_states | Y | — | vlan_stp_states | Repeated VlanStpState. The webhook's map_stp_state helper folds blk/lis/lrn/fwd/dis into the port-status enum. |
| 4008 | switch_vty_lines | Y | — | vty_lines | Repeated VtyLine. |
| 4009 | switch_cpu_load | Y | — | cpu_loads | |
| 4010 | switch_memory_usage | Y | — | memory_usage | |
| Port — phase 2 — source_subtype 1, extra = port BIA MAC, Cisco only | |||||
| 5000 | port_rx_packets | Y | — | unicast_pkts_ins + multicast + broadcast | Summed in Ruby from three separate counters. |
| 5001 | port_tx_packets | Y | — | unicast_pkts_outs + multicast + broadcast | Likewise. |
| 5002 | port_rx_discards | Y | — | discards_ins | |
| 5003 | port_tx_discards | Y | — | discards_outs | |
| 5004 | port_duplex | Y | — | duplexes | |
| 5005 | port_uptime | Y | — | port_uptimes | |
| 5006 | port_poe_usage | Y | — | port_poe_usages | |
| 5007 | port_tagged_vlans | Y | — | svalue: tagged_vlans | String metric. Keyed with bia_address: nil, unlike its neighbours. |
| 5008 | port_access_vlan | Y | — | access_vlans | Same nil-BIA keying. |
| 5009 | port_native_vlan | Y | — | native_vlans | Same nil-BIA keying. |
The rXg computes all twelve of these and hands them to the webhook, which drops them because
ATT_PROTOBUF_MEASUREMENT_TYPES has no matching key. No log line, no error — the
select just narrows the array. Note that this includes every byte counter and every port
speed/status value, three of which schema_notes.md documents as already having
assigned protobuf IDs from the old scheme.
| measurement_id | Cisco | Ruckus | Why it is missing |
|---|---|---|---|
| switch_temperature | Y | — | Pure name mismatch. The map's key is temperature; the producer emits switch_temperature. One string away from working. |
| bytes_rx | Y | — | schema_notes.md assigns RX_BYTES = 108. Never added to the map. |
| bytes_tx | Y | — | TX_BYTES = 109. Same. |
| speed | Y | — | IF_SPEED = 87. Same. |
| connection_status | Y | — | IF_OPER_STATUS = 83. Same. (Producer name differs from the notes' status.) |
| radio_channel_list | Y | Y | Map entry exists but is commented out: #'radio_channel_list' => 125. Cisco sends it as svalue. |
| ap_to_client_total_transfer | Y | Y | Map has a placeholder #'…' => ? — protobuf ID never assigned. |
| client_to_ap_total_transfer | Y | Y | Same placeholder. |
| ap_to_client_total_throughput | Y | Y | Same placeholder. Computed as transfer × 8 ÷ window. |
| client_to_ap_total_throughput | Y | Y | Same placeholder. |
| radio_oper_state | Y | — | No protobuf ID proposed anywhere. Cisco-only, sent as svalue. |
| device_uptime | Y | — | Intentional. schema_notes.md: "internal use only in rXg, not mapped to a protobuf ID". |
The four *_total_transfer / *_total_throughput elements are the volumetric ones —
they are also the metrics that the missing SUM() in the continuous aggregates would affect. Assigning them
protobuf IDs and fixing the rollup are the same piece of work viewed from two ends.
40 keys in the map that no code emits. These are commitments, not capabilities. schema_notes.md is candid about it, marking both large blocks "not yet implemented in the rXg repository".
Whole-rXg metrics: no per-device source_id. schema_notes.md proposes
source_subtype 14 (GATEWAY) but flags it uncertain. 3002 is unassigned.
att-templates!20
(ldd/gateway_metrics) is the intended producer, and it targets
hbh/combined-new-schema rather than master.
| Group | IDs | Keys |
|---|---|---|
| DHCP | 3000–3001 | gateway_dhcp_succ_num, gateway_dhcp_fail_num |
| Social-media tonnage | 3003–3004 | gateway_soc_media_tonnage_ds, …_us |
| Total tonnage | 3005–3006 | gateway_total_tonnage_dl, …_ul |
| Passpoint | 3007–3009 | gateway_passpt_tonnage_dl, …_ul, gateway_passpt_clients |
| Non-Passpoint | 3010–3012 | gateway_non_passpoint_tonnage_dl, …_ul, gateway_non_passpoint_clients |
| AAA (internal) | 3013–3016 | gateway_aaa_auth_time_avg, …_time_max, …_succ_num, …_fail_num |
| AAA (external) | 3017–3020 | gateway_external_aaa_auth_time_avg, …_time_max, …_succ_num, …_fail_num |
The notes' original names were period-scoped (PASSPT_TONNAGE_24HR / 30DAY / 365DAY);
the map replaced those with direction-scoped names (_dl / _ul) and no period. Whoever implements the
producer has to settle what window a gateway tonnage value covers — the webhook asserts
collection_interval: 300 for everything it sends.
The absorbed phase-1 radio IDs. schema_notes.md lists
PACKET_RETRANSMIT_AVG 118, LATENCY_AVG 119, JITTER_AVG 120 and
PACKET_LOSS_AVG 121 as radio measurements, but none of 118–121 appear in the map — they were
re-scoped into this sensor block instead. Worth confirming with AT&T that 118–121 are genuinely retired.
We do have the underlying data: sensor ping jitter/loss/RTT already exist in the rXg as SensorMetric.
| Group | IDs | Keys |
|---|---|---|
| Link quality | 2000–2004 | wlan_sensor_packet_retransmit_avg, …_latency_avg, …_jitter_avg, …_packet_loss_avg, …_mos_score |
| Onboarding | 2005–2007 | wlan_sensor_dhcp_time, …_capport_time_avg, …_capport_time_max |
| Services | 2008–2010 | wlan_sensor_dns_average, …_avg_download, …_avg_upload |
| Client attributes | 2011–2016 | wlan_sensor_ssid, …_rssi, …_client_to_ap_mcs, …_primary_channel, …_channel_width, …_phyrate |
No AAA block here, although the notes ask for five WLAN_SENSOR_AAA_* measurements. Those look
to have become the gateway 3013–3020 range.
| ID | Key | Status |
|---|---|---|
| 4001 | temperature | Name mismatch with the producer's switch_temperature and an int collision with switch_poe_budget. Two bugs in one entry. |
| 4004 | switch_description | Notes say "intended but not currently implemented in rXg". |
| 5010 | port_description | A descriptions KPI exists on the Cisco class but is excluded from PORT_KPIS_FOR_REPORT, so nothing emits it. |
How AT&T tells one measurement apart from another. Set once per element by the producer, then stamped by the webhook.
| Field | Set by | Value |
|---|---|---|
| measurement_id | producer | Snake-case name; the webhook rewrites underscores to spaces before sending. |
| measurement_type | webhook | The protobuf int from the map. |
| source_id | producer | AP ethernet MAC, or switch primary MAC. source_id_type 1 = MAC. |
| extra | producer | Radio slot ID (AP) or port BIA MAC (switch). |
| source_subtype | producer | 0 AP, 1 switch. The proto enum also defines CONTROLLER 2, UPS 3, ONT 4, CELL 5, SERVER 6, CLIENT 7, DB 8, APPLIANCE 9, LB 10, GSLB 11, SAAS 12, HA 13, GATEWAY 14 — none of which we emit yet. |
| source_subcategory | producer | Band: 0 2.4G, 1 5G, 2 6G. Radio metrics only; nil elsewhere. |
| reporter_id | webhook | The rXg's own FQDN, from DeviceOption.active.domain_name. Sent with reporter_id_type 1 (MAC) even though it is a domain name. |
| customer_id / venue_id | webhook | From the att_venue_info CustomDataSet. If that record is absent, both silently become "". |
| collection_interval | webhook | Hard-coded 300 for every measurement, with the comment "time in seconds?". The Ruckus report window is actually 15 minutes. |
| timestamp | either | Producer's value if present, else Time.now.to_i at send time. |
EXTRACT_SNR reads client["rssi"]
and EXTRACT_RSSI reads client["receiveSignalStrength"], annotated in the source as
"ruckus messed this up on their end". IDs 115 and 116 are therefore not comparable between a Cisco venue and a
Ruckus venue without knowing this.mcs_avg is inferred, not measured. Both vendors back-solve an MCS index from rate, PHY, NSS and
channel width. Any gap in the PHY or width tables yields no value at all rather than a wrong one — which is the safer
failure, but means missing data is expected for new PHYs.to_kpi_report only appends SNR, RSSI,
MCS and the throughput family when client_count.nonzero?. An idle radio still reports noise, utilisation,
channel and power — so a missing 115 means "no clients", not "no data".client_count_per_ap (111) is emitted once per
radio with the slot in extra. Summing it across an AP is the caller's job.ClientMetric / RadioMetric /
ThroughputMetric and never reach this webhook. A venue on our own hardware reports nothing to AT&T today.Generated 2026-09-17 from the SHAs named at the top. Re-run the extraction before trusting the counts after either branch moves. ← Project context