Skip to content

The rules

Every rule the engine judges with, in the order it runs them, with what each observes, the outcome it gives, why it sits where it does, the setting in the Mist portal that addresses it, and the recordings that confirm it. Reading the verdict explains the same in plain words.

HintEngine picks an outcome from the fixed set: AP side, client side, RF environment, upstream / not Wi-Fi, measurement limit, undecided. Each hint shows its metrics, thresholds and sources. The thresholds live in HintConfiguration; the initial values are assumptions, to be calibrated on the testlab sessions and the cases from the field.

  • Checks. Each rule is a function that finds a hint, passes, or says why it could not run: "too little traffic", "no login captured", "the client's ACKs not in the capture", "AP not heard" ("client not seen" while the client has no BSS yet, its AP's beacons in or not), "client not seen", "no other AP of the network heard", "no 5 or 6 GHz of the network heard", "bands of the client unknown", "client away from the sensor", "no Mist", "no DHCP or DNS from Mist", "no roam", "not seen by the sensor" (a roam between the radios), "reason encrypted (PMF)" (of a disconnect), "retries and rates not measurable", "no capture statistics". A rule that does not apply passes: the RADIUS server with a pre-shared key, the asymmetric link with the AP weaker than −60 dBm at the sensor. A found hint goes before a missing input: a stalled 4-way is a login captured. In a window across a search of the live session for the client (SessionAnalyzer.searches) the three loss rules say "client not seen": the losses as it left and came back do not judge the link, and the scan finds none there. Per reason the step at the desk that lets its rule run, or why there is none, is in HintEngine.remedies (Hints/Steps.swift), which the Overview's Next and the report's "What the recording lacks" read (the app): presentation, not a verdict.
  • The decision. The rules run in order of priority: the measurement, then what ends or blocks a connection, then the causes of a poor link (roaming, coverage, the channel), then the losses they cause. The first hint with a side decides; the others follow as found as well, and one with another side is marked as pointing elsewhere. An observation without a side (outcome undecided) does not decide: losses with nothing to compare, losses towards the AP without Mist or without interference in Mist, losses the reference client does not have, a login that fails for the reference client too (the losses below the table). It names in its text the side it points to where it points to one, "it points towards the AP, unconfirmed", or the candidates where they lie on more than one side. A finding that points elsewhere never overrides the deciding one, however severe: otherwise the order no longer predicts the verdict (the column "Why here" of the table). With only observations the outcome is undecided and the first one is the reason; without any hint the reason is "Nothing abnormal found." with the questions that stayed untested, or "Too little data." when all did. A note (Hint.note) is seen and worth knowing, not abnormal: it neither decides nor makes its question poor, follows the findings, and its question's readout names it (a note of frames sent again by its number, "17% sent again", the note in full in the readout's help); with only notes the reason is "Nothing abnormal found.".
  • A verdict per question. Connection (association, login, disconnects), AP to client, client to AP, coverage, roaming and channel. A question is poor when one of its rules found something, not when it only noted something. Otherwise it takes its grade from its number where it has one (Block Ack success; the AP at the sensor; the channel's QBSS load once congestion ran, Fair from qbssHigh (60 %), Good below it or without one, so a desk on a loaded campus channel never reads Good, and Poor from the finding alone), or is good when a rule that judges it ran: any rule of the connection, the roam rules or the sticky client for roaming (not the probe storm or the band choice alone: neither judges a roam). Without that it is untested. Block Ack success grades delivery: what reached the recipient, an A-MPDU lost whole and delivered on a retry among it, as no Block Ack reports that loss. The share sent again is the airtime the delivery cost: it stands beside the grade and moves it only as a loss rule's finding, since one grade for two measures would hide which of them is poor (the AP45 sent each A-MPDU to the phone three times at 98.6 % BA success). The AP at the sensor stands for the client's coverage only with the client near the sensor: below clientNearSensor the coverage question is untested, as its two rules are, and Mist's client RSSI at the AP, the other direction at another receiver, stays beside it and grades nothing. The delivery readouts name what their grade judges ("99.1% delivered"), the share sent again over the same span under it, in Fair's color from retransmitHigh. Each question lists what its rules could not check. Without a finding the outcome is undecided, and the reason is "nothing abnormal found" only while no question is poor; a question poor by its number names itself, poor without a finding, with the text of its note where it has one.
  • Windows. HintFacts covers the whole session or a TimeWindow of it: the metrics from the per-second buckets that start in the window (BA success, capture share, retry bit, rates, airtime, the client's signal), the AP's and the neighbors' signal from the beacons heard in it (the AP's from minimumBeacons (20) beacons and probe responses on, in the window or the session, so its coverage question and readout are untested below that once the client's BSS is known, with "too few beacons of the AP" where its BSS was heard and "AP not heard" where not; a neighbor or co-channel radio not heard in it, as in focus, with its signal over the session), the channel utilization the AP reports in its BSS Load (QBSS) as the mean of its beacons in it, the events, handshakes, EAP exchanges, roams and anomalies within it, and the serving BSS, profile and AKM as of its end: without a (re)association before the end, the BSS of the client's data at the end, not that of the session's end. The client's signal at the sensor is the session's in a window without its frames, and "roamed" counts every roam attempt at or after the window's start, completed or not. The drops of the capture are the session's, whatever the window. HintEngine.report judges the whole session and sliding windows of windowLength (20 s) every windowStep (5 s); per rule the window with the largest Hint.severity (the loss, the dB past the threshold, the load of a busy channel) is the one shown, the whole session on a tie, so a problem of twenty seconds in ten minutes is not averaged away. The hint also lists every stretch where its rule found it (Hint.windows, its windows merged where they overlap: a finding's findings, a note's notes), which the time axis draws; a rule that counts events lists the moment of each event instead (Hint.times, each window's first, Hint.time the first of all). The windows lie on the grid within the session, plus, once the session no longer grows, one more on the grid that takes in the last interval: live and in a replay before its end a window is judged once it is full, so a finding's window never moves back. Rules that exclude each other within one set of facts (the three loss rules; sticky client and weak coverage; the two SAE rules) can each find a hint in another window: the report keeps one per group, the most severe loss, else the first in priority. A finding of a rule takes the place of its note from another window, however severe the note; a note excludes nothing. A hint found in a window names it (Hint.window) and makes its question poor; a hint about an event (a login, a disconnect, a refusal, a roam, a channel switch, a probe storm) names its moment (Hint.time); what a rule could not check, it checks over the whole session. A report over a chosen window judges that window only.
  • Disconnects. Who ended a connection comes from the order of the frames, which PMF and the 4-way fix whatever the vendor: the client's own frame is the client's; the AP's within 1 s after the client's EAPOL-Logoff (encrypted after the keys, known by its size) or after its own disconnect is the client's; the AP's protected one while a radio listened on the link through the second before, and nothing of the client leaving in it, is the AP's own; the AP's in the clear on a connection with keys and PMF says only that the AP dropped the keys first. The client's own disconnect within 1 s after an AP's disconnect the client began is the rest of its leaving (restOfLeaving): the phone's protected disassociation after its SA Query to the AP45's reason 36 in the clear went unanswered; its encrypted reason leaves no question untested. A reason code is a label: the standard defines what each code means (IEEE 802.11-2020, 9.4.1.7), not which one an AP sends when. After the frames it decides a side only where the standard ties it to one event and its class gives one (the sender's 3 and 8, the AP's 5, 6 and 7), and then where a vendor's use of it was measured (Mist's 2 for the portal's Reconnect, 23 and 36 after the client's logoff; UniFi's 1 for a kick). With a vendor whose codes were not measured, a reason alone gives no side: undecided, with the order of the frames shown. The rules read the class of a code, not its number; the table, the classes, the measured uses and how the vendor is known are on reason codes. The hint's text and its evidence ("who began") name what decided: the frames, the standard or the vendor's measured use, or "reason codes not measured for this vendor".
  • The measurement limit comes first: drops of at least 1 % of what linkside-cap received over the session, or at least 100 on one radio within a second, summed over every restart of the capture. Gaps in the sequence numbers are shown but are no measurement limit: UL OFDMA always produces them. So is a radio that heard the client on 5 or 6 GHz through a USB 2 port (SessionAnalyzer.slowPorts): a busy channel does not fit through it and the radio loses frames that no counter shows (sensor-link.md).
  • The retry bit and the MCS of a direction count only with a capture share of at least 90 % in that direction (minimumCaptureShare): with the fast frames of five recordings dropped, the retry bit left the whole direction's by more than 2 points from 76 % up and from 93 % down, the median MCS fell by one from 75 % (eht-capture.md). And only with enough Block Acks for its BA success: without them a few null frames with the retry bit read as 100 % retries (testlab-co-channel, before the traffic).
  • A session is recorded because a user has a complaint; the app does not ask whether it remains. With nothing found the verdict reads "Nothing abnormal found.", after Stop also the Overview's headline, not "No clear cause"; beside a note "No finding, only notes." and on the Overview "No finding", as a note can read a third of the frames sent again, which "nothing abnormal" would talk over. Either way a clean link, the cause beyond the Wi-Fi or at the client itself (a laptop at full CPU), which the sensor cannot tell apart. wifi-fine, which named upstream by elimination, was removed on 2026-10-26. An answer to the former "Problem still there" in an older session.json is ignored when read.
  • The reason of an encrypted disconnect comes from a Mist client event of the same kind within 3 s, after the clock correction, on the same BSS where Mist names one; the evidence names Mist as its source.
  • The report names under each finding the lever on the network side (HintEngine.levers, in Hints/Levers.swift, the table's column Lever): the setting in the Mist portal, by its label there (checked on the Mist test site, 2026-10-23). On the WLAN's page: Fast Roaming (Default, Opportunistic Key Caching (OKC), .11r), Band Steering, Radio Band, Minimum client RSSI per band under Geofence (with Block clients having RSSI below the minimum), Data Rates (Compatible, No Legacy, High Density, Custom Rates) and Security Type (WPA3 or OWE, Enterprise (802.1X) or Personal (SAE), Enable WPA3+WPA2 Transition). In the band's settings of the RF template (Site > Radio Management): Channel Width, Power (Automatic, or Set power with a min and max) and Channels (Automatic, or Set allowable channels, DFS marked dfs). On the AP's page, the band's Configuration (5 GHz Configuration, Dual Band Radio Config): Channel Width, Channel and Power instead of Use site setting. The portal has no limit on the number of clients (its Client Limit is the Per-Client Rate Limit) and no setting for BTM. The app does not show the lever: it is the remediation line of the ticket. A note names none, and neither does a rule that points at the client where the network does not steer its choice (a missing capability, its credentials, its own disconnect), the sensor or the upstream. A rule that points at the client's choice of AP or band names the setting that steers it: the sticky client, the band choice, the weaker roam, ping-pong. A lever can hold for some outcomes of a rule only: fast roaming for roam-full-login on the AP side, not for the client that skips the 802.11r the network offers. No lever, AP side or RF environment: slow-roam (its wait can be the client's, the AP's or the RADIUS server's), ap-disconnect (reason 2 after a completed login is a person's or a script's Reconnect, the other reasons the AP's decision, not one setting), ap-disconnect-all, beacon-loss and cached-key (the AP's state: a restart, a config push, a key cache it lost), join-unanswered (undecided), and the three loss rules (the channel, which congestion names where it is busy).
  • Confirmed in a recording. Per rule the recordings in testdata/sessions that confirm it (HintEngine.confirmations, in Hints/Confirmations.swift, and the last column of the table below): a finding, not a note, with the side its expected.json gives, in a recording that expects a finding, and not of a rule its expected.json names, every finding of it in that recording wrong beside the right outcome (falseFindings); the synthetic sessions confirm nothing. A finding of a rule not listed (Hint.unconfirmed) decides as any other, and says what it rests on: "unconfirmed" beside its title on the Overview, with "Rule not yet confirmed in a recording." under its evidence, in the help of the readout that names it, and in the report under the finding. A note carries no mark. ConfirmationTests recomputes the list from verdict.json and expected.json and checks the table against it: a recording that confirms a rule adds it in the same commit.

In order of priority (HintEngine.rules):

Rule Question Observation Outcome Why here Lever Confirmed in
drops – The drops of the measurement limit above measurement limit The measurement first: frames the capture misses look like losses and missing handshakes to every rule after it. – –
usb-port – A radio that heard the client on 5 or 6 GHz through a USB 2 port (usb in linkside-cap's start line below 5000), whatever the load: the port loses Block Acks before linkside-cap counts a drop; untested in a recording made before linkside-cap gave the speed (2026-10-23) measurement limit As drops: a port that loses Block Acks uncounted makes losses of its own. – testlab-usb2-port
not-heard – No frame from the client's address and no (re)association of it in a capture of at least notHeardSpan (30 s), over the whole session: possibly a Wi-Fi 7 multi-link address, whose link MACs only a reconnect names; untested in a shorter capture measurement limit Every rule after it needs the client's frames: recorded, not analyzed. – testlab-mlo-not-heard
credentials connection EAPOL M2 without M3 with a pre-shared key, an SAE confirm the AP refuses or leaves unanswered, or an EAP-Failure not more than 5 s after the client's last response; the reference client does connect client side (credentials); undecided when the reference client fails too The logins before the disconnects and refusals: a login that fails ends in the AP's deauthentication or a new join, and the cause is the login. – testlab-wrong-psk, testlab-wrong-psk-psk-iphone, testlab-wrong-psk-psk-mac, testlab-wrong-psk-sae-iphone, testlab-wrong-psk-sae-mac
cached-key connection EAPOL M2 without M3 after a cached key (PMKID, no EAP) AP side – – –
login-keys connection EAPOL M2 without M3 after EAP-Success upstream (keys from the RADIUS server) – – –
sae-keys connection EAPOL M2 without M3 with SAE (the AP accepted the password) or OWE (no password) undecided (the keys, on either side) – – –
m3-missed connection EAPOL M3 without M4 in a 4-way that ended (a disconnect, a new join or a new 4-way), the client having acknowledged M1: none of the AP's attempts of M3 acknowledged, or M3 acknowledged and no M4. The client's ACK is the ACK to the AP within ctsWindow on the TSF after the key frame (KeyAckTracker); without the ACK to M1 the capture does not tell, "the client's ACKs not in the capture" client side (it does not hear the AP after its M2, or does not answer M3); undecided when the reference client fails too – – testlab-4way-ack, testlab-wifi7-one-link
sae-config connection SAE status 77 without a successful SAE after it, or reason 17 (any AKM); the reference client with the same AKM fails too AP side (WLAN config) Excludes sae-compatibility on the same facts: the reference client with the same AKM decides between them, and the report keeps the first. the WLAN's Security Type –
sae-compatibility connection The same; the reference client with the same AKM does connect, or is not there client side (compatibility) As sae-config. – testlab-sae-group
channel-switch channel The client's AP announces a channel switch (CSA or Extended CSA) with mode 1 away from a DFS channel; any other switch RF environment (radar); AP side (RRM or config) Before the disconnects: a CSA explains the client leaving its AP and the beacons stopping on the old channel (beacon-loss). the band's Channels in the RF template, without DFS; a fixed Channel on the AP's page –
ap-disconnect-all connection Deauth or disassoc from the client's AP to the broadcast address (its reason is readable with PMF: BIP protects, it does not encrypt) AP side (every client disconnected) Before ap-disconnect and beacon-loss: a deauthentication of every client is the restart or config push that also disconnects this one and stops the beacons. – testlab-ap-reboot, u7-phone-search-copies
association-refused connection The AP refuses an association or a non-SAE authentication outside a roam with status 17, 37, 53, 54, 55 or 82 AP side The refusals before the disconnects: a refused join names the reason for the client being off the network that a disconnect after it hides. the WLAN's Band Steering and Minimum client RSSI (82), Fast Roaming (53–55); none for 17 –
association-incompatible connection The same with status 10, 13, 18, 31, 40 to 46 or 72 client side (capabilities or security) As association-refused; the statuses of the two do not overlap. – –
join-unanswered connection At least 2 authentication or (re)association requests the AP leaves unanswered for 1 s, after the last one it answered, and no connection after them, not within 120 s after the AP refused a login of the client with no connection since (penaltyWindow): an AP's silence to a client it just refused is the refusal's, as Mist's penalty box held commits unanswered up to 82 s (mist-events.md) undecided (the AP does not hear the client, or ignores it) – – –
radius-disconnect connection Deauth or disassoc from the AP to the client with Mist's 802.1X failure (MARVIS_EVENT_CLIENT_AUTH_FAILURE) within 3 s that ties it to a RADIUS server not answering: code 514 in the event's text ("Timeout, Radius Server Failed to respond to request(514)"). Mist's structured fields do not carry it (the failure has type_code 50, authorization_reason_code 23, the 802.1X failure of any kind, and the AP's deauthentication reason_code 2), so the session keeps the codes in parentheses of the text (text_codes in mist.json), not the text; recordings from before 2026-10-26 lack them. Text: "Disconnected by the AP: the RADIUS server did not answer in time." upstream / not Wi-Fi Before ap-disconnect, which leaves such a disconnect out, as do encrypted-disconnect and poor-channel. – –
ap-disconnect connection Deauth or disassoc from the AP to the client, on the BSS the client is on, also when it rejoins at once, not one the client began (the frames: its EAPOL-Logoff or own disconnect within 1 s before; or its vendor's measured use, which client-disconnect reads); not the classes of a login (13–24, 48–51, and 2 while the client logs in: without a completed 4-way or FT reassociation since its last join, and without a protected frame), a BSS transition (12) or a poor channel (34). Reason 2 after a completed login is the AP ending a working connection: Mist's Reconnect. AP side where the frames show the AP began (protected while the sensor heard the link, also without a reason), the standard ties the code to the AP (5, 6, 7, and the AP's own 3 and 8), or the vendor's use of it was measured (UniFi's kick is reason 1, Mist's Reconnect 2, protected or on a connection without PMF: reason codes); otherwise undecided, "reason codes not measured for this vendor". Reason 4 (inactivity) alone goes by the client's frames to the AP in the 60 s before (inactivityWindow, ClientActivity): frames the AP acknowledged with an ACK or Block Ack, "The AP timed out a client it heard"; frames it left unacknowledged, "The AP did not hear the client"; none, "The AP timed out an idle client"; without a capture of that minute untested ("no capture before the disconnect"). Beside another reason from the AP it counts as that one AP side; undecided where neither the frames, the standard nor a measured use shows who began; reason 4 alone: AP side where the AP acknowledged the client's frames, undecided where it did not, a note for an idle client Before beacon-loss and client-disconnect: what the AP ends explains the beacon gap of its restart and the client's own deauthentication after it. – testlab-ap-kick, testlab-ap-kick-eduroam, testlab-ap-kick-eduroam-iphone, testlab-ap-kick-eduroam-mac, testlab-ap-kick-psk-iphone, testlab-ap-kick-psk-mac, testlab-ap-reboot
beacon-loss connection No beacon of the serving BSS for 2 s while the sensor kept listening AP side Before client-disconnect: a client that leaves an AP that stopped beaconing follows the AP. – testlab-ap-reboot
poor-channel connection Deauth or disassoc with reason 34, the code the standard ties to a poor channel RF environment – the band's Channels in the RF template; a fixed Channel on the AP's page –
client-disconnect connection The client sends a deauth or disassoc itself with the code the standard ties to the sender leaving (3 or 8), or the AP sends it one the client began: within 1 s after the client's EAPOL-Logoff, in the clear or encrypted and known by its size, or by its vendor's measured use (a Mist AP's 23 and 36 after the logoff: reason codes); without a join within 60 s, judged only once those 60 s are in the capture: until then untested, "waiting for the client to rejoin" (live, between Wi-Fi off and on; a recording that ends sooner). Not the AP's answer to the client's own disconnect, which counts itself, nor the client's disconnect of a join without its keys: a login it gave up, which the login rules read client side After the AP's disconnects, the beacon loss and the refusals: a client leaving is its own choice only where the AP gave it no cause. – testlab-client-leaves-eduroam-iphone, testlab-client-leaves-eduroam-mac, testlab-client-leaves-psk, testlab-client-leaves-psk-iphone, testlab-client-leaves-psk-mac-menu, testlab-client-leaves-sae-iphone, testlab-client-leaves-sae-mac
client-silent connection After the client's last frame the AP's RTS and Block Ack Requests to it go unanswered, at least 20 together over at least 10 s (silentFrames, silentFor; the one recording has 2,077 over 159 s, no other more than 2), with no data from the AP, which it sends only after a CTS, so the AP did not hear the client either; no CTS or Block Ack that answers an RTS (TxopTracker), no CTS, ACK or Block Ack to the client, no disconnect from either side, on the AP that serves the client, not a roam a search found, and the client at least −60 dBm at the sensor in its last frame, otherwise untested ("client away from the sensor": the sensor may just have lost it, with the data the AP beamforms). Not back within 60 s, judged only once those 60 s are in the capture. An AP that sends without RTS shows none of this client side (its Wi-Fi went off, or it left the channel without a word) After client-disconnect: a client that says it leaves has that rule. – testlab-client-leaves-psk-mac-settings
encrypted-disconnect connection A deauth or disassoc to or from the client on its BSS whose reason PMF encrypted and Mist did not give within 3 s, and whose frames do not show the AP began (that one ap-disconnect takes); the client's own only without a join within 60 s, and once those 60 s are in the capture, as client-disconnect reads it, and not right after an AP's disconnect the client began (the rest of its leaving), the AP's also when the client joins again, as ap-disconnect does. Not one to the broadcast address (BIP keeps its reason readable), not one on a BSS the client had left a note: who sent it, which kind and when, with the client's next join; the question stays untested on the reason After the disconnect rules: it says what they could not judge. – –
roam-refused roaming The new AP refuses a roam with status 17, 53, 54, 55 or 82 (other statuses only in the timeline; 30 is PMF at work) AP side Before the roam rules: a refused attempt makes the roam after it slow or a full login. the WLAN's Band Steering and Minimum client RSSI (82), Fast Roaming (53–55); none for 17 –
radius-latency connection RADIUS latency ≥ 1 s, an EAP response the AP never answers for 1 s or more, or an EAP-Failure ≥ 5 s after the client's response. The AP got the response: it did not send its request again. A response never answered names what ended the wait (EAPExchange.Unanswered): the AP asking for the identity again (the AP45 after 29.9 s) or disconnecting the client, "RADIUS server not answering"; the client starting over (EAPOL-Start or a join) or leaving, "Slow RADIUS server", "until the client started over": the server took at least that long and may have answered after it (the phone gave up after 6.9 s at 12:05:35 on 2026-10-29, Mist naming the server's silence, 514) upstream / not Wi-Fi Before ip-services, in the order of a connect: DHCP comes after the login the RADIUS server holds up. – ap45-radius-slow-login, ap45-radius-unanswered-login
ip-services connection Mist's DHCP, gateway ARP or DNS event of the client failed, or took at least 3 s (DHCP) or 500 ms (ARP, DNS), as the AP saw it, or Mist found the client's address wrong; the worst per kind, in the window, or over the whole session from its first frame on with the association (time_since_assoc) by its last. The first that is poor in the order of a connect (DHCP, the address, the gateway, DNS) decides: the gateway and DNS fail with a bad address. The types from Mist's list (MistView.IPService.types, mist-events.md): DHCP Success, ACK, Timed Out, Denied and Aborted; Blocked: Static IP Address, Invalid IP and Bad IP Assigned; Gateway ARP Success and Timeout; DNS Success and Failure; Blocked: Static DNS Address. DHCPv6, DHCP Inform, ARP to other hosts and DNS Recovery only in the timeline: beside IPv4 and SLAAC a failed DHCPv6 seldom keeps a client offline. Untested without Mist, or without such an event upstream / not Wi-Fi: the AP times ARP and DNS beyond the air, and a bad address comes from the DHCP server; undecided for DHCP alone on a lossy link (BA success below 90 % in a direction, or the frames sent again in a direction), since its offer and ack cross the air, and for an invalid address, a static address from another network being the client's and an address from another VLAN the network's (after a DHCP that failed it takes that DHCP's side, and a blocked or bad address goes before it); client side for a DNS server or a static IP address of the client's own that the network blocks – – testlab-ip-services-dns
roam-full-login roaming A roam with a full 802.1X login takes ≥ 150 ms while the new AP offers 802.11r for the client's AKM (the FT variant of its own AKM family), not within 5 s after that AP refused an 802.11r attempt; or the AP ignores the client's PMKID, or the network offers no 802.11r for that AKM client side (skips 802.11r); AP side – the WLAN's Fast Roaming (AP side only) –
slow-roam roaming A roam without a full login takes ≥ 150 ms the side that kept the other waiting (RADIUS counts for the AP) – – –
ping-pong roaming ≥ 3 roams back and forth between two APs within 60 s client side; AP side when the AP sent the client away each time (a readable BTM request, or reason 12); undecided when it may have each time (with PMF a BTM request is an encrypted action frame; a Block Ack setup, known by its size and its answer, does not count) – Power in the RF template or on the APs' pages; Band Steering –
sticky-client roaming A neighbor with the same SSID is ≥ 8 dB stronger, the serving AP at most −70 dBm at the sensor, the client at least −60 dBm at the sensor, no roam; the reference client does roam client side (sticky) Before weak-coverage, one of the two per report: a neighbor 8 dB stronger makes the weak AP the client's choice. the WLAN's Minimum client RSSI (Geofence) or Data Rates –
band-choice roaming The client on 2.4 GHz alone (with MLO no link on 5 or 6 GHz) while a BSS with its SSID and its AKM (not known: one the serving BSS takes) on 5 or 6 GHz is at least −65 dBm at the sensor (goodSignal), on a band the client is known to use: of the BSSs it was on or tried to join, of its (re)association requests, or named by its capabilities (HE's widths in 5 GHz, the HE 6 GHz Band Capabilities, a 5 GHz channel among its Supported Channels; a phone's request on 2.4 GHz names none of them), the client at least −60 dBm at the sensor. A finding where 2.4 GHz costs the client: the channel busy as congestion reads it, or with all its data in the window on 2.4 GHz BA success below 97 % in a direction, the frames sent again in a direction, or a median downlink MCS ≤ 3; otherwise a note (the idle phone of ap45-phone-band-roam). The other band's signal from the window, or over the session where the focus filter left its beacons out. Untested without a 5 or 6 GHz BSS of the network heard, or when the client is not known to use the band of the good one client side (its choice of band); a note Before weak-coverage: with the network's 5 or 6 GHz good here, a weak 2.4 GHz is the client's choice of band. Band Steering; less Power on 2.4 GHz; 2.4 GHz off in the WLAN's Radio Band –
weak-coverage coverage The serving AP at most −72 dBm at the sensor, no AP of the network ≥ 8 dB stronger on the band, the client at least −60 dBm at the sensor (otherwise the losses speak for themselves), with losses (BA success below 97 % in a direction) or a median downlink MCS ≤ 3, or too little traffic to tell over the whole session (not a quiet window of a session with traffic) AP side (coverage) Before congestion and the losses: congestion's low-MCS branch asks for a good signal, so it assumes the signal judged first, and a weak client on a busy channel has no SINR margin to lose: the lever is its coverage. two-way-loss leaves its facts to it. an AP nearer; Power, as far as the uplink reaches –
asymmetric-link coverage The sensor hears the AP at least −60 dBm, Mist hears the client at most −75 dBm, the client at least −60 dBm at the sensor; Power Capability max of the client shown AP side (AP power or RRM) Before congestion, as weak-coverage: the lever of a client the AP hears poorly is the link budget, not the channel. less Power (RF template, the AP's page); the WLAN's Minimum client RSSI –
weaker-roam roaming A completed roam to an AP ≥ 6 dB weaker at the sensor, same band, the client at least −60 dBm at the sensor, and no BTM request, encrypted action frame that may be one (with PMF a BTM request is an encrypted action frame; a Block Ack setup, known by its size and its answer, does not count) or disconnect with reason 12 or an encrypted reason from the AP in the 5 s before (an answer within 0.5 s after the client's own BTM query or encrypted action frame is not steering) client side After coverage: a roam to a weaker AP where the band offers no AP 8 dB stronger is the coverage, not the client's choice. the WLAN's Minimum client RSSI (Geofence) –
congestion channel At least 3 other AP radios on the channel at ≥ −82 dBm, or QBSS ≥ 60 %, with retries ≥ 10 % in each direction the retry bit is measurable in (one is enough when the other is not), or a median downlink MCS ≤ 3 at ≥ −65 dBm; or the load alone: QBSS ≥ 80 % (qbssBusy) beyond the client's own airtime, with the client's traffic in the window (BA success in a direction), its frames getting through: the client waits for the air, as a saturated hub slows every host without a CRC error (testlab-co-channel-iphone: QBSS 92 % for two minutes, the retry bit 3 to 5 %, BA success 99.7 % and up, the client's RTS unanswered 8 to 15 % against 0.5 % before it). The client's own airtime is that of its data frames both ways over the window, each direction scaled up by the share of it the sensor captured (the frames it misses are the fast ones, so this overstates it, the right side for a guard), since the AP's QBSS counts its own transmissions: the U7 read 95 % under its own client's download with the client idle (testlab-co-channel, before the traffic), so the user's own speed test is no busy channel. 80 % leaves less than a fifth of the air for everyone else; the three co-channel recordings sit at 81 to 95 % under the load, every quiet one below 41 % (2.4 GHz at home the highest), nothing between them is measured, and item 040 checks it on the campus. Untested without the AP's QBSS and fewer co-channel radios, and on a busy channel without the client's traffic (the idle client of testlab-co-channel before the traffic) RF environment (congestion) Before the losses: the busy channel explains the retries and losses it causes (testlab-co-channel); on the load alone there are none to explain, and a weak AP decides before it. the band's Channels and Channel Width in the RF template; less Power on the co-channel APs testlab-co-channel, testlab-co-channel-iphone, testlab-co-channel-mac
uplink-loss client to AP UL success below 90 %, or 15 % or more of the client's frames sent again (retransmitHigh, as towards the client), by the retry bit with at least 90 % of the uplink captured (retransmitCaptureShare); Mist gives no share of the uplink sent again (what rx_retries counts is open, mist-events.md). DL not lost on either measure, or at its usual level beside BA success far under the client's own (two-way-loss). Mist sees a low client SNR or high util_non_wifi at the AP; otherwise (no Mist, no interference in Mist, DL fair or without traffic) undecided, and the frames sent again with UL success not below 90 % a note (a phone in normal use sent 15 to 23 % again in windows of a few hundred frames, u7-phone-search-again, ap45-phone-reconnect) AP side; undecided; a note Excludes two-way-loss and downlink-loss on the same facts (one direction or both); across windows the report keeps the most severe loss of the three, so their order decides nothing. – –
two-way-loss both directions A loss both ways, each by its success below 90 % or by its frames sent again as downlink-loss and uplink-loss count them, unless weak coverage takes it; the reference client fine both ways on the measures that found them, on the client's BSS (on another BSS no side); the AP's frames sent again mostly right after the client's wakes undecided, as in downlink-loss; the radio environment only with the client near the sensor (clientNearSensor). Without the reference client beside it with both measures, frames sent again are a finding only as a jump: both ways at least 7.5 points above the client's own level (levelJump), not mostly right after wakes (testlab-intermittent-loss-psk-iphone); otherwise a note (ap45-phone-reconnect). BA success low one way and the other way at its usual level is no loss both ways: a note (testlab-intermittent-loss-psk-iphone-moved), from 7.5 points under the client's own BA success that way's rule RF environment; client side; undecided; a note As uplink-loss. – testlab-intermittent-loss, testlab-intermittent-loss-psk-iphone, testlab-intermittent-loss-psk-iphone-moved
downlink-loss AP to client DL success below 90 %, or 15 % or more of the AP's frames sent again (retransmitHigh): BA success counts a frame delivered on a retry as delivered, an A-MPDU lost whole among them. The retry bit counts them with at least 90 % of the downlink captured (retransmitCaptureShare), Mist's count of the minutes the window overlaps with less (mistSentAgain, text and evidence marked Mist): the sensor misses the AP's fast frames, so the retry bit of the rest reads high (mist-events.md). UL not lost on either measure, or at its usual level beside BA success far under the client's own (two-way-loss), and good; the reference client on the client's BSS gets its data, on the measure that found the loss (on another BSS no side), UL fair or without traffic, or at least two thirds of the loss or of the frames sent again right after the client's wakes from power save (powerSaveLossShare: its power save, the AP's rate after the pause, or interference near it; of Mist's count not: Mist does not say when in its minute, and the retry bit, which would, counts only where it takes Mist's place, as below that its share rests on a handful of frames); the worst window by the larger of the two. Without a reference client on the client's BSS to compare, frames sent again with DL success not below 90 % and losses mostly right after the wakes are a note (a phone in normal use, testlab-long-quiet); the radio environment only with the client at least −60 dBm at the sensor, otherwise undecided (u7-phone-ft-roam) RF environment; client side; undecided; a note As uplink-loss. – testlab-power-save-second-client
low-mcs AP to client A median downlink MCS ≤ 3 with the AP at least −65 dBm at the sensor and the client at least −60 dBm, on a channel congestion does not find busy, with the data getting through: DL success not below 90 % and the AP's frames not sent again from 15 % (a rate control lowers the rate for losses; the loss rules judge them). Only with at least 90 % of the downlink captured (rateCaptureShare): the sensor decodes the AP's frames up to the MCS its own SNR allows, so the frames it misses are the fast ones and the median of the rest reads low; a median above 3 passes at any share. The reference client on the client's BSS, with as much of its downlink captured, at a median above 3 client side; undecided (the client's receiver or power save, the AP's rate control, or interference near the client; the reference client low too: the AP's rate control or interference here) After the losses: a rate control lowers the rate for losses, so a low rate with losses is theirs, and the rule passes on them. – –
probe-storm roaming 20 probe requests in 10 s while connected (after a successful association or data with an AP, until a disconnect) client side Last among the client-side rules: a client searching while connected is often the symptom of the weak or lossy link a rule before it names. – –

The losses that stay observations, and why. The sensor hears the client's surroundings, not the AP's, so a loss takes a side only from a comparison: the other direction getting through, the reference client on the client's BSS, or Mist at the AP.

  • uplink-loss without Mist, or with Mist seeing no interference at the AP (no low client SNR, no util_non_wifi): it points towards the AP, unconfirmed. With the downlink fair or without traffic it has nothing to compare and no side. The client's frames sent again with BA success not low are then a note, as the AP's are towards the client: the readout names the share, the grade stays that of BA success.
  • two-way-loss on frames sent again alone, both ways, without the reference client beside it to compare on them: a note, as a phone in normal use sends 20 % again in every window. A jump both ways is a finding: the sender repeats what an oven takes, BA success stays at 99 %, and the share sent again leaves the level the client has without it.
    • The level (UsualLevel): the median of the session's windows on the client's BSS that do not overlap the window judged, from four of them on (levelWindows), of the share sent again and of BA success. A client's level differs per BSS, so a roam starts a level of its own, and a window across it counts for neither, as a window across a search does not. The median is unweighted: a client whose busy windows all sit below 90 % among quiet ones reads as a deep loss, which those windows are. Like against like: Mist's count against Mist's, the retry bit against the retry bit, as Mist's reads higher. Live those are the windows before it; after the end those after it count too, so a window at the start of a session has a level then. Frames sent again alone in a window without one stay a note. A window chosen to look at takes the level of the windows outside it. The figures: the oven.
    • One direction at its usual level is no loss both ways. BA success low the other way, at least 7.5 points under the client's own (levelJump) or with that level below 90 % itself, is a loss that way alone, for downlink-loss or uplink-loss; less is a dip, the note "Losses towards the client" or "Losses towards the AP", as a phone's bursts of wakes give. Over the whole session there is no level, so a loss that lasts is a finding there too. The recordings hold one such window, 89.6 % in a burst of wakes, 5.0 points under the level, and none of the deeper kind.
    • A session needs about a minute of usual traffic on each side of the problem: with 30 s the oven's windows raise the level, and in testlab-intermittent-loss-psk-iphone-moved the jump falls from 9.6 to 6.1 points.
    • An oven takes the sensor's capture of the downlink below 90 % as well, so the AP's side rests on Mist's count: without Mist there is no finding, and live it comes with the count of the oven's minute, 25 and 67 s after the oven's end in the two recordings. Right after wakes is not known of Mist's count, as in downlink-loss, so the condition does not hold it back there. Live, replayed with Mist's polls as they came, the finding followed the note 42 and 62 s later with Mist's count, and without Mist at the end of the oven's windows, and went away again in none of the three oven recordings; ap45-phone-reconnect kept its notes. The stretches of a rule's notes are every window it noted something in, under the title of the worst: a rule has one hint, and a stretch chosen says which note it is.
  • two-way-loss and downlink-loss with the reference client getting through on a BSS not known to be the client's: it says nothing about this AP, and the loss points towards the client, unconfirmed.
  • downlink-loss with the uplink fair or without traffic: nothing to compare. Losses mostly right after the client's wakes from power save: its power save, the AP's rate after the pause or interference near it, which one session cannot tell apart (testlab-client-leaves-eduroam). Without a reference client on the BSS, frames sent again with BA success not low, or losses after wakes, are a note, as a phone in normal use has them (testlab-long-quiet).
  • two-way-loss and downlink-loss with the client weaker than −60 dBm at the sensor: its coverage or interference where it is, which the sensor does not hear (u7-phone-ft-roam).
  • low-mcs without the reference client beside it: the client's receiver or power save, the AP's rate control, or interference near the client; with the reference client low too: the AP's rate control or interference here, not the client.

A window that holds the start of a connection judges it with the rest of it: the loss rules hold no seconds after a join back and ask for no more frames than BA success does, and their text and evidence say it ("the window ends 7 s after the reconnect", "the window starts 400 ms after the reconnect"; after the roam or the login; "after the last of its 2 joins"; HintEngine.afterJoin). A window holds it where the keys of a successful join (M4, or the accepted response with FT or without RSN) came at most 3 s before its start (joinStart) and at least a metrics interval before its end, so it holds seconds after them; a window longer than the scan's 20 s, one the user chose, holds none, the start weighing too little in it (HintFacts.Joins.holds). In the recordings the first three seconds after a join's keys carried a few dozen to two hundred of the AP's frames, 15 to 22 % of them sent again after three of five reconnects, where the same phone sends 13 to 34 % again over the rest of its session; leaving out 3 or 5 s moved a window by a few points either way, and would hide a loss right after a join. The window of ap45-phone-video-reconnect that ends 7 s after the reconnect, 29 of 89 frames sent again, most of them in the phone's wakes 5 and 6 s after its keys, is a fair note (power-save.md, 2026-10-31).