diff --git a/.env.example b/.env.example index 2c21388..49c53c5 100644 --- a/.env.example +++ b/.env.example @@ -286,15 +286,16 @@ DATA_RETENTION_INTERVAL_HOURS=24 # (with a "show potential spam" toggle on the Messages page). Nothing is ever # dropped; the score is stored and the display layer filters on it. # -# Off by default. FEATURE_SPAM_DETECTION is the single switch operators set: in +# On by default. FEATURE_SPAM_DETECTION is the single switch operators set: in # Docker Compose it drives the backend SPAM_DETECTION_ENABLED for the collector -# (scoring + sweep) and the api (hide-filter), and exposes the UI toggle. -# FEATURE_SPAM_DETECTION=false +# (scoring + sweep) and the api (hide-filter), and exposes the UI toggle. Opt out +# by setting it to false. +# FEATURE_SPAM_DETECTION=true # Backend operational switch, read by the collector + api. Compose derives it from # FEATURE_SPAM_DETECTION (SPAM_DETECTION_ENABLED=${FEATURE_SPAM_DETECTION}); set it # directly only when running the services without Compose. -# SPAM_DETECTION_ENABLED=false +# SPAM_DETECTION_ENABLED=true # Score at/above which a message is treated as likely spam (hidden by default in # the API, logged at WARNING by the collector). Read by the collector + api. @@ -585,11 +586,11 @@ SYSTEM_MAINTENANCE=false # Packets page is ON by default. This var also drives raw-packet capture # on the collector via Compose (RAW_PACKET_CAPTURE_ENABLED=${FEATURE_PACKETS}). # FEATURE_PACKETS=true -# Spam detection is OFF by default. This var also drives the backend scoring + +# Spam detection is ON by default. This var also drives the backend scoring + # hide switch on the collector/api via Compose -# (SPAM_DETECTION_ENABLED=${FEATURE_SPAM_DETECTION}). See the Spam Detection -# section above for the scoring tuning vars. -# FEATURE_SPAM_DETECTION=false +# (SPAM_DETECTION_ENABLED=${FEATURE_SPAM_DETECTION}). Set to false to opt out. +# See the Spam Detection section above for the scoring tuning vars. +# FEATURE_SPAM_DETECTION=true # ------------------- # Contact Information diff --git a/docker-compose.yml b/docker-compose.yml index 004391e..d991c1c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -240,8 +240,9 @@ services: - RAW_PACKET_CAPTURE_ENABLED=${FEATURE_PACKETS:-true} - RAW_PACKET_RETENTION_DAYS=${RAW_PACKET_RETENTION_DAYS:-7} # Spam detection (derived from FEATURE_SPAM_DETECTION so one var drives the - # backend switch and the web toggle together). Off by default. - - SPAM_DETECTION_ENABLED=${FEATURE_SPAM_DETECTION:-false} + # backend switch and the web toggle together). On by default; opt out with + # FEATURE_SPAM_DETECTION=false. + - SPAM_DETECTION_ENABLED=${FEATURE_SPAM_DETECTION:-true} - SPAM_SCORE_THRESHOLD=${SPAM_SCORE_THRESHOLD:-0.65} - SPAM_WINDOW_SECONDS=${SPAM_WINDOW_SECONDS:-300} - SPAM_PATH_HOPS=${SPAM_PATH_HOPS:-3} @@ -315,8 +316,9 @@ services: - REDIS_CACHE_TTL=${REDIS_CACHE_TTL:-30} - REDIS_CACHE_TTL_DASHBOARD=${REDIS_CACHE_TTL_DASHBOARD:-30} # Spam detection: hide-filter switch + threshold (bridged from - # FEATURE_SPAM_DETECTION so it tracks the collector and web toggle). - - SPAM_DETECTION_ENABLED=${FEATURE_SPAM_DETECTION:-false} + # FEATURE_SPAM_DETECTION so it tracks the collector and web toggle). On by + # default; opt out with FEATURE_SPAM_DETECTION=false. + - SPAM_DETECTION_ENABLED=${FEATURE_SPAM_DETECTION:-true} - SPAM_SCORE_THRESHOLD=${SPAM_SCORE_THRESHOLD:-0.65} command: ["api"] healthcheck: @@ -410,9 +412,9 @@ services: - FEATURE_RADIO_CONFIG=${FEATURE_RADIO_CONFIG:-true} # Packets page is on by default; this also drives collector capture. - FEATURE_PACKETS=${FEATURE_PACKETS:-true} - # Spam detection toggle is off by default; this also drives the backend + # Spam detection toggle is on by default; this also drives the backend # scoring/hide switch on the collector and api. - - FEATURE_SPAM_DETECTION=${FEATURE_SPAM_DETECTION:-false} + - FEATURE_SPAM_DETECTION=${FEATURE_SPAM_DETECTION:-true} command: ["web"] healthcheck: test: diff --git a/docs/configuration.md b/docs/configuration.md index f02faab..0ab694e 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -130,11 +130,11 @@ The collector automatically cleans up old event data and inactive nodes. Retenti Scores each message's spam likelihood at ingest, stores the score on the message row, and hides likely-spam by default in the API (with a "show potential spam" toggle on the Messages page). Nothing is ever dropped — the design is reversible and the threshold can be retuned without reprocessing. -Off by default. `FEATURE_SPAM_DETECTION` is the single switch operators set: in Compose it drives the backend `SPAM_DETECTION_ENABLED` for the **collector** (scoring + the background re-scoring sweep) and the **api** (the hide-filter), and exposes the UI toggle (see [Feature Flags](#feature-flags)). Set `SPAM_DETECTION_ENABLED` directly only when running services without Compose. +On by default; opt out with `FEATURE_SPAM_DETECTION=false`. `FEATURE_SPAM_DETECTION` is the single switch operators set: in Compose it drives the backend `SPAM_DETECTION_ENABLED` for the **collector** (scoring + the background re-scoring sweep) and the **api** (the hide-filter), and exposes the UI toggle (see [Feature Flags](#feature-flags)). Set `SPAM_DETECTION_ENABLED` directly only when running services without Compose. | Variable | Default | Read by | Description | | --- | --- | --- | --- | -| `SPAM_DETECTION_ENABLED` | `false` | collector, api | Operational switch for scoring + hiding. In Compose, derived from `FEATURE_SPAM_DETECTION` (`SPAM_DETECTION_ENABLED=${FEATURE_SPAM_DETECTION}`) | +| `SPAM_DETECTION_ENABLED` | `true` | collector, api | Operational switch for scoring + hiding. In Compose, derived from `FEATURE_SPAM_DETECTION` (`SPAM_DETECTION_ENABLED=${FEATURE_SPAM_DETECTION}`) | | `SPAM_SCORE_THRESHOLD` | `0.65` | collector, api | Score at/above which a message is treated as likely spam (hidden by default; logged at `WARNING`) | | `SPAM_WINDOW_SECONDS` | `300` | collector | Sliding window (seconds) for frequency counts | | `SPAM_PATH_HOPS` | `3` | collector | Leading origin-side hops that form the `path_prefix` | @@ -211,7 +211,7 @@ Control which pages are visible in the web dashboard. Disabled features are full | `FEATURE_CHANNELS` | `true` | Enable the `/channels` page | | `FEATURE_RADIO_CONFIG` | `true` | Show radio config panel on home page | | `FEATURE_PACKETS` | `true` | Enable the `/packets` raw-packet browser. In Compose this also drives `RAW_PACKET_CAPTURE_ENABLED` on the collector | -| `FEATURE_SPAM_DETECTION` | `false` | Show the "show potential spam" toggle on `/messages`. In Compose this also drives `SPAM_DETECTION_ENABLED` on the collector + api — see [Spam Detection](#spam-detection) | +| `FEATURE_SPAM_DETECTION` | `true` | Show the "show potential spam" toggle on `/messages`. In Compose this also drives `SPAM_DETECTION_ENABLED` on the collector + api — see [Spam Detection](#spam-detection) | **Dependencies:** Dashboard auto-disables when all of Nodes/Advertisements/Messages are disabled. Map auto-disables when Nodes is disabled. Members auto-disables when OIDC is disabled (set via `OIDC_ENABLED`). diff --git a/docs/upgrading.md b/docs/upgrading.md index b280327..7c4f4c5 100644 --- a/docs/upgrading.md +++ b/docs/upgrading.md @@ -10,7 +10,7 @@ Each message is now scored for spam likelihood **at ingest** and the score is st The scorer combines two windowed signals over a sliding time window: a **path signal** (joint count of the same origin-side path prefix + normalised sender) and a **name signal** (count of the same normalised sender, after stripping a trailing digit/space suffix so rotating `bob1`/`bob2`/`Bob 3` collapse to `bob`). When the path is too short to be useful — including the **zero-hop case** where an observer sits right next to the sender — the name signal stands on its own at full weight, so local/zero-hop spam can still be flagged. A background sweep re-scores recent rows with hindsight (a symmetric window) so the leading edge of a burst is caught once its peers arrive. -**Off by default. No action required to upgrade** — leave `FEATURE_SPAM_DETECTION` unset and messages behave exactly as before (the new columns stay null and nothing is hidden). +**On by default.** After upgrading, the collector scores new messages and the API hides likely-spam from the Messages page automatically — operators get protection without any configuration. To opt out, set `FEATURE_SPAM_DETECTION=false` and recreate the `collector`, `api`, and `web` services. Existing messages ingested before the upgrade keep null scores and are never hidden (no backfill), so only newly-ingested traffic is affected. **Database migration required:** @@ -24,8 +24,8 @@ This adds three nullable columns to the `messages` table — `path_prefix`, `sen | Variable | Default | Description | | ------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------- | -| `FEATURE_SPAM_DETECTION` | `false` | The single operator switch. Shows the "show potential spam" toggle on the Messages page. In Compose this **derives** the backend `SPAM_DETECTION_ENABLED` for the collector and api. | -| `SPAM_DETECTION_ENABLED` | `false` | Backend operational switch read by the collector (scoring + sweep) and api (hide-filter). In Compose derived from `FEATURE_SPAM_DETECTION`; set directly only when running without Compose. | +| `FEATURE_SPAM_DETECTION` | `true` | The single operator switch. Shows the "show potential spam" toggle on the Messages page. In Compose this **derives** the backend `SPAM_DETECTION_ENABLED` for the collector and api. Set to `false` to opt out. | +| `SPAM_DETECTION_ENABLED` | `true` | Backend operational switch read by the collector (scoring + sweep) and api (hide-filter). In Compose derived from `FEATURE_SPAM_DETECTION`; set directly only when running without Compose. | | `SPAM_SCORE_THRESHOLD` | `0.65` | Score at/above which a message is treated as likely spam — hidden by default in the API, logged at WARNING by the collector. Read by collector + api. | **Scoring tuning (collector only; consulted only when detection is enabled):** @@ -41,11 +41,11 @@ This adds three nullable columns to the `messages` table — `path_prefix`, `sen | `SPAM_WEIGHT_NAME` | `0.25` | Weight of the name signal | | `SPAM_RESCORE_INTERVAL_SECONDS` | `120` | Background re-scoring sweep cadence (`0` disables the sweep) | -**Feature ↔ backend split:** the UI toggle is served by the `web` app while scoring runs in the `collector` and the hide-filter in the `api` — separate processes with separate settings. Docker Compose links them: setting `FEATURE_SPAM_DETECTION=true` enables scoring + sweep on the collector, the hide-filter on the api (both via `SPAM_DETECTION_ENABLED=${FEATURE_SPAM_DETECTION}`), and the toggle in the web UI. Operators running the processes directly can set `SPAM_DETECTION_ENABLED` independently. +**Feature ↔ backend split:** the UI toggle is served by the `web` app while scoring runs in the `collector` and the hide-filter in the `api` — separate processes with separate settings. Docker Compose links them: `FEATURE_SPAM_DETECTION` (default `true`) drives scoring + sweep on the collector, the hide-filter on the api (both via `SPAM_DETECTION_ENABLED=${FEATURE_SPAM_DETECTION}`), and the toggle in the web UI. Operators running the processes directly can set `SPAM_DETECTION_ENABLED` independently. -**API:** message endpoints gain a `spam_score` field and an `include_spam` query parameter. By default the API hides rows scoring at/above `SPAM_SCORE_THRESHOLD`; `include_spam=true` returns them (rows with a null score — i.e. ingested before the feature was on, or while it was off — are always shown). With the feature off the filter is a no-op. +**API:** message endpoints gain a `spam_score` field and an `include_spam` query parameter. By default the API hides rows scoring at/above `SPAM_SCORE_THRESHOLD`; `include_spam=true` returns them (rows with a null score — i.e. ingested before the upgrade, or while the feature was opted out — are always shown). With the feature opted out the filter is a no-op. -To enable, set `FEATURE_SPAM_DETECTION=true` in your `.env` and recreate the `collector`, `api`, and `web` services. All variables are passed through `docker-compose.yml` automatically. +The feature is on by default and all variables are passed through `docker-compose.yml` automatically — no configuration is needed to adopt it. To opt out, set `FEATURE_SPAM_DETECTION=false` in your `.env` and recreate the `collector`, `api`, and `web` services. ### Docker Compose `pull_policy` removed from base diff --git a/src/meshcore_hub/common/config.py b/src/meshcore_hub/common/config.py index 6c08f39..43c9884 100644 --- a/src/meshcore_hub/common/config.py +++ b/src/meshcore_hub/common/config.py @@ -563,10 +563,11 @@ class WebSettings(CommonSettings): default=True, description="Enable radio config panel on home page" ) feature_spam_detection: bool = Field( - default=False, + default=True, description=( - "Expose the 'show potential spam' toggle on the messages page; in " - "Compose this also drives the backend SPAM_DETECTION_ENABLED switch" + "Expose the 'show potential spam' toggle on the messages page (on by " + "default); in Compose this also drives the backend " + "SPAM_DETECTION_ENABLED switch" ), )