Based on PR #1183 (trendal), locally hardened for the v2.2 line.
A mutual `apDevice` reference is not evidence of orientation: UISP also
fills it on the AP end of PtP/bridge links. Trust the reference only when
one end is positively labelled as AP/station, and decline both-AP,
both-station or unlabelled mutual references so the result does not depend
on argument order.
Adds 9 regression tests (13 directionality tests total).
Credit: PR #1183 (trendal).
Backport target: public v2.2 line (develop).
Both workflows ran their full pipelines on every push, including
docs-only and opposite-language changes, which wasted runner time and
reported failures unrelated to the change under test.
Add a shared detect-changes workflow that diffs the pushed or PR range
against per-group patterns and exposes a matched output. The heavy jobs
run only when their group changed, or when detection itself fails, so a
broken detector cannot silently skip checks. Tag pushes and unknown
events fall back to running everything.
Include .github/scripts/test-changed-files.sh, a manual harness for the
detection logic that follows the repo's existing shell self-tests.
Builds a circuit-hash index from the combined catalog before refreshing descriptors, so dynamic and removed circuits cannot trigger per-circuit fallback scans while the counter lock is held. Clarifies the module documentation and fixes the Spanish parent-node wording.
Live circuits now follow renames and re-parenting because descriptors refresh from the catalog on each snapshot, while circuits removed from configuration keep their last-known descriptor and continue contributing to their last known parent. Documents the tracker-side lock constraint, releases the throughput table lock before the counter merge, adds a first-miss descriptor recovery test, and applies rustfmt to the new hunk.
Reuses ParentNodeLookup so node attribution follows the same id, name, and attachment-alias precedence as the rest of the runtime, and prefers the published effective parent when capturing circuit identity. Adds an alias-resolution test and clarifies the snapshot lock-order comment.
Captures circuit identity and parent when a counter first receives traffic, so circuits removed from configuration keep contributing to their last known parent instead of dropping out of node totals. Resolves parent nodes by stable id before name, fills descriptors at read time, skips zero-byte deltas, and documents the counter lock ordering. Expands tests for the absent config section, disabled snapshots, root-attached circuits, id-preferred node resolution, and stable circuit ordering.
Documents the optional [byte_counters] section, counter reset semantics, subtree-inclusive node totals, and the GET /byte_counters endpoint in English and Spanish.
When [byte_counters] enabled = true, the one-second throughput tracker batches each circuit's actual-byte deltas into a cumulative counter map. Node totals are rolled up through the runtime network tree when the bus is queried, so node values include descendants. Counters are in-memory and reset when lqosd restarts.
Adds GetByteCounters with cumulative per-node and per-circuit byte counter payloads. The request is read-only, so it fails fast on timeout and needs no daemon-side mutation.
Adds a [byte_counters] section that is absent by default, so existing configuration files keep working unchanged. The section will gate cumulative per-circuit and per-node byte counter collection in lqosd.
The forward loop (for i in 1..60) copies slot 0 into all 59 older slots, so median_latency() always returns the previous sample instead of a 60-sample median. Iterating in reverse preserves the history and drops the oldest sample.
findBandwidthMins() reused one minDownload/minUpload counter for both each node's own minimum and the running sibling total, so every sibling after the first inherited the circuit minimums of the siblings before it. Those inflated minimums are written to queuingStructure.json and become HTB rates, which can guarantee child nodes more bandwidth than their parent supplies.
Reset the counters per node and keep a separate running total for the parent. Also fix the no-minimum-key fallback, which used minUpload for the download minimum.
The function is hoisted to module level so the behavior can be unit tested, with regression coverage for sibling accumulation and order, nested roll-up, and the download fallback.
Consolidate the atomic writer into src/atomic_io.py and route the
remaining runtime/generated writes through it so an interrupted write
cannot leave a truncated file. Preserve destination ownership and
permissions across the rename, and treat an unreadable or non-object
network.json as a validation failure instead of crashing the scheduler.
The Powercode preseem API returns customer and equipment ids as ints
while service ids come back as strings, so the service lookup in
createShaper() never matched and zero customers were imported. All ids
are now normalized to strings before use.
The integration now also pulls the list_sites endpoint and builds the
network hierarchy from it: sites are added as site nodes, site
infrastructure equipment that has subscribers attached (APs, routers,
backhauls) becomes AP nodes, and customers are parented onto the AP
their equipment references, falling back to a sibling device's AP and
then to the root. Display names are trimmed and de-duplicated so the
topology compiler's exact-match parent name validation passes.
Keep queued Bakery commands intact while lqosd checks local .keys state, releasing the gate for both successful and non-fatal cache outcomes without tying startup to Insight network availability.