Repository navigation
feat(notify): adaptive offline threshold and certain node analytics (#2260) - #2262
Conversation
Review notesReviewed the delta 1. A stalled feed can still send offline mails for floor-clamped nodes
Two ways to close it: measure node silence against 2.
|
000e458 to
7ad251a
Compare
|
Review feedback addressed (commit
Not changed, with reasons:
|
Follow-up on the review notes aboveRead the delta These changes read correctly:
Still open from the review notes:
New with the longest-zero-run ruleOne real outage of N hours in the learning week (N under about 17, above that the node is not learnable) raises the learned window to N+1 h for the rest of that week. A second outage is then mailed after N+1 h instead of the floor. QuestionWhich should the zero-run rule cover: every empty run (current), only runs that recur (for example on at least two days), or only runs up to a cap (for example 6 h), with longer ones treated as outages? |
7ad251a to
b0a37f2
Compare
|
Review notes addressed (commit Answers to the questions: silence is measured against the newest ingested packet; the zero-run rule covers only runs that recur and are at most 6 h, longer or one-off runs are outages.
|
Review of
|
|
Review feedback addressed (commit
Not changed: the small |
…pa-clawbot#2260) Part 2 of Kpa-clawbot#2260, on top of the certain-liveness fix. Adaptive offline threshold (userManagement.notifications.adaptiveOffline, off by default). A watched node's node.offline window is learned from its own certain traffic: certain packets per hour over the week before its last certain packet (ending there, not at now, keeps an outage from dragging the rate down until it reads "back online"), λ the 10th percentile so quiet nights do not alert, window 14/λ hours (silence at that rate has under a one-in-a-million chance), clamped to [floorMinutes, the role's silent window]. Nodes with λ < 1/hour, under a day of history or fewer than minObservers observers keep the fixed window: one observer dropping out must not read as the node going offline. The notifier caches each learned window for 10 minutes and drops unwatched nodes. The Kpa-clawbot#2260 repeater (~840 packets a day) would have been mailed about 30 minutes into its outage instead of never. Node analytics: each timeline bucket carries certain, the part that can only be this node (certainFor: the packet-level form of the certainHeard rule). Availability and the longest silence come from certain buckets only, and the longest silence includes one still running. The chart stacks certain (--accent) and uncertain (--text-muted). Cost: CertainActivity walks a week of packets per watched node, at most once per node per 10 minutes, with the read lock taken per node: 12 ms for 50 busy repeaters with 6,000 packets each (~0.25 ms per lock hold). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
a287de4 to
e1eee43
Compare
Release notes for v3.15.0: `docs/release-notes/v3.15.0.md` and the `CHANGELOG.md` entry. The release workflow uses the notes file as the GitHub release body. ## What is in it - 77 commits since v3.14.0 (76 merged pull requests plus this one): 27 fix, 23 perf, 19 feat, 3 test, 2 ci, 2 docs, 1 chore. Nineteen feats, so minor. - "Read this before upgrading" first. It covers: - the liveness change (#2261, #2262); - the `users.db` v6 migration and what it means for a rollback (#2174); - the backfill at every ingestor start (#2133) and the 24 h planner-statistics refresh (#2158); - the caches that trade freshness for latency (#2165, #2222, #2147, #2156); - changes in hop names and region placement (#2188, #2190, #2234, #2245, #2220); - the role thresholds on favorites (#2215); - the geo-filter save on a single-file mount (#2137); - the `/api/stats` polling in hidden tabs (#2162). - Features, fixes, performance, then tests/CI/docs. - 29 issues closed, taken from each pull request's `closingIssuesReferences`. - Contributors: pull request authors and issue reporters with counts. The commit co-author trailers only name the pull request's own author or tooling. ## How it was checked - I read every pull request body. Every number in the notes comes from a pull request body. - I checked the config keys and defaults against `config.example.json` on `2bb000f2`. - I checked the UNASKED and opt-in claims for #2125, #2133, #2235 and #2239 against the source. - For the other pull requests I relied on their bodies and did not open the diffs. ## Not covered - The uncertain count is a single count on one staging instance on the day of the change (1,682 repeaters and rooms). It is not a before/after comparison. - #2133 gives no measured cost for its backfill on a large database, and the notes say so. ## After merge Tag `v3.15.0` on the merge commit once its `:edge` image exists. Then check in the registry that `v3.15.0`, `v3.15`, `v3` and `latest` share one digest, and that the release has the notes as its body and both `corescope-decrypt` binaries. --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Part 2 of #2260. Builds on #2261 (certain liveness): review/merge that first; until then this diff also shows its commit.
Adaptive offline threshold
userManagement.notifications.adaptiveOffline— off by default:The fixed
infraSilentHours(72 h) treats every repeater the same. With this on, a watched node'snode.offlinewindow is learned from its own certain traffic (the #2261 rule):floorMinutes, the role's silent window].Kept on the fixed window: λ < 1/hour, under 24 h of history in memory, or a 10th-percentile hour heard by fewer than
minObserversobservers (one observer dropping out must not read as the node going offline). Silence is measured up to the newest packet in the store, so a stalling feed stops every node's clock. A node stored offline comes back only on evidence from the moment it went offline on. The notifier caches each learned window for 10 minutes and drops unwatched nodes.For the #2260 repeater (~840 packets/day) the mail would have gone out about 30 minutes into the outage, instead of never (or 72 h with #2261 alone).
Certain node analytics
activityTimelinebucket carriescertain: the part that can only be this node (certainFor, the packet-level form of thecertainHeardrule).TimeBucket.Certainisomitempty, so other endpoints are unchanged.--accent) and uncertain (--text-muted) — existing theme variables, so no new customizer entry. Descriptions updated.Performance
CertainActivitywalks a week of packets per watched node, at most once per node per 10 minutes, with the read lock taken per node:Node analytics adds one
certainForper packet of the requested node (a prefix-map lookup, or the cached decoded JSON for its own packets).Tests
adaptiveOfflineAfter: busy repeater hits the floor; 5/hour; quiet nights set the rate; > 10 % empty hours, short history, too few observers → fixed.CertainActivityends at the last certain packet and counts only certain packets — verified red by mutating the window to end at now.certainFor,longestSilence(incl. running silence), config defaults,/api/nodes/{pk}/analyticssplits a shared-prefix bucket.NodeAnalyticsTimeline.series(newtests/unit/test-node-analytics-certain-timeline.js).cmd/servergo test ./...andtest-all.shpass locally, also on a trial merge into a downstream fork.Validation
Server on the freshened e2e fixture: analytics buckets carry
certain(e.g. 89 of 90 packets certain for one repeater). No browser screenshot: Playwright isn't installed on this machine.Later (rule 8)
floorMinutes/minObserversare server config, not theme settings; an admin UI for notification settings would be the place, not the customizer.🤖 Generated with Claude Code