mirror of
https://git.churchofmalware.org/leviathan/OVERWATCH
synced 2026-09-24 08:35:03 +00:00
v0.5.10 — recalibrate distance curves so range can't move the threat tier
The scores were already absolute, but the tier is max(score) over everything *reported* and the range slider decides what is reported — so the setting still leaked into the alarm. Measured against a real 195-node cache: standing still and dragging the slider from 300 m to 500 m flipped the app from GREEN to YELLOW with nothing physical changing. The fix is calibration, not plumbing. Every curve now crosses below the YELLOW line at roughly the distance the thing stops being able to act on you. A Flock camera reads plates at ~30-50 m, so it is RED on top of it, ORANGE at 100 m, and GREEN by 500 m — still drawn on the map, just no longer an alarm. Waze keeps a wider band deliberately: a police car covers 700 m in under a minute, a bollarded camera never moves. Aircraft are unaffected, since that scanner uses its own ranges rather than the slider. The main-screen slider is relabelled "show within" to say what it actually is — a view control, not a sensitivity control. Verified on device: sweeping 200 m -> 4900 m leaves the tier at GREEN while the reported count goes 0 -> 133, and standing 29 m from a real camera reads 89 RED, then 50 at 252 m and 41 at 373 m. Scores match the falloff formula exactly. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RsfSpnwuxCkcXKkD9XH8SR
This commit is contained in:
co-authored by
Claude Opus 5
parent
32e2ef2606
commit
19622b87e1
@@ -80,17 +80,27 @@ freshness window, because police move and a surveyed camera does not.
|
||||
|
||||
| Distance | DeFlock ALPR | Waze police (fresh) |
|
||||
|---|---|---|
|
||||
| 0 m | 92 RED | 80 ORANGE |
|
||||
| 50 m | 85 RED | 75 ORANGE |
|
||||
| 100 m | 77 ORANGE | 70 ORANGE |
|
||||
| 200 m | 60 YELLOW | 62 YELLOW |
|
||||
| 600 m | 45 YELLOW | 49 YELLOW |
|
||||
| 1200 m | 35 GREEN | 41 YELLOW |
|
||||
| 3000 m | 22 GREEN | 28 GREEN |
|
||||
| 0 m | 95 RED | 80 ORANGE |
|
||||
| 50 m | 85 RED | 78 ORANGE |
|
||||
| 100 m | 72 ORANGE | 70 ORANGE |
|
||||
| 200 m | 55 YELLOW | 62 YELLOW |
|
||||
| 350 m | 42 YELLOW | 52 YELLOW |
|
||||
| 500 m | 35 GREEN | 47 YELLOW |
|
||||
| 1000 m | 26 GREEN | 34 GREEN |
|
||||
| 3000 m | 18 GREEN | 23 GREEN |
|
||||
|
||||
A fixed ALPR peaks higher and decays faster than a crowd-sourced police pin:
|
||||
its position is surveyed and exact, while a Waze report is a coarse pin on a
|
||||
car that may be moving toward you.
|
||||
Each curve crosses below the YELLOW line (40) at roughly the distance the thing
|
||||
stops being able to act on you. A Flock camera reads plates at ~30–50 m, so it
|
||||
is RED on top of it, ORANGE at 100 m, and GREEN by 500 m — still drawn on the
|
||||
map, just not an alarm. Waze keeps a wider band on purpose: a police car covers
|
||||
700 m in under a minute; a bollarded camera never moves.
|
||||
|
||||
**This calibration is what makes a single range slider safe.** The tier is
|
||||
`max(score)` over everything reported, and the slider decides what gets
|
||||
reported — so with looser curves, standing still and dragging it from 300 m to
|
||||
500 m flipped the app GREEN → YELLOW with nothing physical changing. Now
|
||||
sweeping 200 m → 4900 m leaves the tier untouched, while standing 29 m from a
|
||||
camera still reads **89 RED**.
|
||||
|
||||
The user-facing circle uses the full 4-tier mapping. Cross-source corroboration
|
||||
naturally pushes the global max upward (a BLE OUI hit *and* a DeFlock map
|
||||
@@ -264,12 +274,13 @@ Tap the gear icon in the top-right.
|
||||
- **Detection sources**: toggle BLE / WiFi / DeFlock / Waze / Aircraft / Commercial independently.
|
||||
Changes take effect on the next Start. While scanning, a **Restart scan to
|
||||
apply** button appears that does `stop()` + `start()` in one tap.
|
||||
- **Detection radius** lives on the **main screen**, under the map — it's the
|
||||
one setting you reach for while moving, so it isn't buried in Settings.
|
||||
100 m – 5000 m, default 500 m, committing on release rather than per-pixel so
|
||||
dragging it doesn't restart the location scanners on every frame. It sets what
|
||||
gets reported and what the circle draws — *not* how alarming a hit is, which
|
||||
is purely a function of real distance.
|
||||
- **Range** (`show within`) lives on the **main screen**, under the map — it's
|
||||
the one control you reach for while moving. 100 m – 5000 m, default 500 m,
|
||||
committing on release rather than per-pixel so dragging it doesn't restart the
|
||||
location scanners on every frame. It is a **view control, not a sensitivity
|
||||
control**: it sets what the circle draws and what the drill-down lists, and
|
||||
nothing else. Scores come from real distance alone, so widening it adds dots
|
||||
and rows but cannot change the threat tier.
|
||||
- **Waze police feed**: paste your own OpenWeb Ninja API key — see
|
||||
[Waze setup](#waze-setup-bring-your-own-api-key). Stored encrypted on-device
|
||||
(Android Keystore), never baked into the APK. Empty = Waze source off.
|
||||
@@ -317,6 +328,7 @@ field-tested. Current release **v0.5.7**. Notable changes:
|
||||
- v0.5.7 — Citizen source **removed entirely** (client, scanner, scoring, settings, map dots and the drill-down row). Its endpoint now returns HTTP 410 Gone, so there was nothing left to degrade gracefully into. OVERWATCH is now a five-source app: BLE, WiFi, DeFlock, Waze, Commercial.
|
||||
- v0.5.8 — **AIRCRAFT source**: police / surveillance aircraft overhead via free community ADS-B feeds, matched against a bundled 1,971-entry registry of US law-enforcement airframes (regenerate with `scripts/gen-le-aircraft.py`), plus loiter/orbit detection so unlisted aircraft circling overhead still register. Overpass query widened to speed cameras and generic surveillance nodes, each scored on its own curve. DeFlock/Waze/aircraft all scored by continuous distance falloff. New [SOURCES.md](SOURCES.md) reference.
|
||||
- v0.5.9 — Detection-radius slider moved onto the main screen (under the map, where you reach for it while moving) and a source-color legend added beneath the circle: ALPR red, speed camera amber, other cameras gray, Waze police blue, aircraft violet.
|
||||
- v0.5.10 — Recalibrated every distance curve so the range slider can no longer move the threat tier: each crosses below YELLOW at roughly the distance the thing stops being able to act on you (ALPR is RED on top of it, GREEN by 500 m). The main-screen slider is relabelled `show within` to say what it is — a view control, not a sensitivity control.
|
||||
|
||||
## License
|
||||
|
||||
|
||||
+23
-8
@@ -347,16 +347,31 @@ decides what gets *reported*, never how alarming it is.
|
||||
|
||||
| Distance | ALPR | Speed camera | Generic camera | Waze police | Aircraft |
|
||||
|---|---|---|---|---|---|
|
||||
| 0 m | 92 | 75 | 55 | 80 | 88 |
|
||||
| 50 m | 85 | 70 | 48 | — | — |
|
||||
| 200 m | 60 | 52 | 38 | 62 | — |
|
||||
| 600 m | 45 | 40 | 30 | 49 | — |
|
||||
| 1000 m | — | — | — | — | 80 |
|
||||
| 1500 m | 30 | 28 | 22 | — | — |
|
||||
| 3000 m | 22 | 20 | 18 | 28 | 68 |
|
||||
| 6000 m | — | — | — | — | 55 |
|
||||
| 0 m | 95 | 78 | 55 | 80 | 88 |
|
||||
| 50 m | 85 | 70 | 46 | 78 | — |
|
||||
| 100 m | 72 | 63 | 42 | 70 | — |
|
||||
| 200 m | 55 | 50 | 34 | 62 | — |
|
||||
| 350 m | 42 | 38 | 28 | 52 | — |
|
||||
| 500 m | 35 | 32 | 26 | 47 | — |
|
||||
| 1000 m | 26 | 27 | 20 | 34 | 80 |
|
||||
| 3000 m | 18 | 16 | 14 | 23 | 68 |
|
||||
| 15000 m | — | — | — | — | 30 |
|
||||
|
||||
**Every curve crosses below 40 (YELLOW) at roughly the distance the thing stops
|
||||
being able to act on you.** That is not cosmetic — it is what makes a single
|
||||
range slider safe. The on-screen tier is `max(score)` over everything reported,
|
||||
and the slider decides what is reported, so loose curves let the setting leak
|
||||
into the alarm: measured against a real 195-node cache, standing still and
|
||||
dragging from 300 m to 500 m flipped the app GREEN → YELLOW with nothing
|
||||
physical changing. After recalibration, sweeping 200 m → 4900 m leaves the tier
|
||||
untouched (reported items 0 → 133), while standing 29 m from a Flock camera
|
||||
still reads 89 RED.
|
||||
|
||||
Aircraft are exempt from the range slider entirely — `AircraftScanner` uses its
|
||||
own 15 km reporting range (8 km for unregistered contacts), because an aircraft
|
||||
orbiting overhead is still watching you from a distance at which a camera
|
||||
cannot see you at all.
|
||||
|
||||
A surveyed ALPR peaks highest and decays fastest — its position is exact and it
|
||||
cannot see you from a kilometre away. A Waze report is a coarse pin on a car
|
||||
that may be moving toward you. An aircraft decays slowest of all, because one
|
||||
|
||||
@@ -14,8 +14,8 @@ android {
|
||||
applicationId = "org.soulstone.overwatch"
|
||||
minSdk = 26
|
||||
targetSdk = 35
|
||||
versionCode = 25
|
||||
versionName = "0.5.9"
|
||||
versionCode = 26
|
||||
versionName = "0.5.10"
|
||||
}
|
||||
|
||||
// Fixed debug keystore committed to the repo (a debug key is non-secret — its
|
||||
|
||||
@@ -284,11 +284,23 @@ object ConfidenceEngine {
|
||||
* by [falloff].
|
||||
*
|
||||
* These are **absolute distances, deliberately not a fraction of the user's
|
||||
* detection radius.** A camera 200 m away is exactly as close whether the
|
||||
* radius slider reads 300 m or 5 km, so it has to score the same either
|
||||
* way; keying off the radius would make the threat level move when the
|
||||
* user touched a setting, which is the opposite of what the number means.
|
||||
* The radius decides what gets *reported*, never how alarming it is.
|
||||
* range setting.** A camera 200 m away is exactly as close whether the
|
||||
* slider reads 300 m or 5 km, so it has to score the same either way.
|
||||
*
|
||||
* That alone was not enough, and the gap is worth recording. The on-screen
|
||||
* tier is `max(score)` over everything *reported*, and the slider decides
|
||||
* what gets reported — so with the original curves, standing still and
|
||||
* dragging the slider from 300 m to 500 m flipped the app GREEN -> YELLOW
|
||||
* with nothing physical changing (measured against a real 195-node cache).
|
||||
* The scores were absolute but the tier still leaked the setting.
|
||||
*
|
||||
* The fix is calibration, not plumbing: each curve now crosses below the
|
||||
* YELLOW line (40) at roughly the distance the thing stops being able to
|
||||
* act on you. A Flock camera reads plates at ~30-50 m, so it is RED on top
|
||||
* of it, ORANGE at 100 m, and GREEN by 500 m — visible on the map, not an
|
||||
* alarm. Widening the view then adds dots and list rows but cannot change
|
||||
* the tier. Waze keeps a wider alert band on purpose: a police car covers
|
||||
* 700 m in under a minute, a bollarded camera never moves.
|
||||
*
|
||||
* A fixed ALPR's position is surveyed and exact, so it stays alarming
|
||||
* closer in and decays slowly. The 50 m and 200 m values are carried over
|
||||
@@ -296,7 +308,8 @@ object ConfidenceEngine {
|
||||
* unchanged.
|
||||
*/
|
||||
private val DEFLOCK_FALLOFF = arrayOf(
|
||||
0f to 92f, 50f to 85f, 200f to 60f, 600f to 45f, 1500f to 30f, 3000f to 22f
|
||||
0f to 95f, 25f to 90f, 50f to 85f, 100f to 72f, 200f to 55f,
|
||||
350f to 42f, 600f to 30f, 1500f to 22f, 3000f to 18f
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -304,7 +317,8 @@ object ConfidenceEngine {
|
||||
* you if you're speeding past it — relevant, not alarming.
|
||||
*/
|
||||
private val SPEED_CAMERA_FALLOFF = arrayOf(
|
||||
0f to 75f, 50f to 70f, 200f to 52f, 600f to 40f, 1500f to 28f, 3000f to 20f
|
||||
0f to 78f, 50f to 70f, 150f to 55f, 300f to 42f, 500f to 32f,
|
||||
1500f to 22f, 3000f to 16f
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -313,7 +327,7 @@ object ConfidenceEngine {
|
||||
* distance and never drives the tier on its own.
|
||||
*/
|
||||
private val CAMERA_FALLOFF = arrayOf(
|
||||
0f to 55f, 50f to 48f, 200f to 38f, 600f to 30f, 1500f to 22f, 3000f to 18f
|
||||
0f to 55f, 50f to 46f, 150f to 38f, 300f to 30f, 800f to 22f, 3000f to 14f
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -322,7 +336,8 @@ object ConfidenceEngine {
|
||||
* the old flat baseline of 55.
|
||||
*/
|
||||
private val WAZE_FALLOFF = arrayOf(
|
||||
0f to 80f, 100f to 70f, 300f to 55f, 800f to 45f, 2000f to 32f, 4000f to 25f
|
||||
0f to 80f, 100f to 70f, 300f to 55f, 600f to 44f, 900f to 36f,
|
||||
2000f to 26f, 4000f to 20f
|
||||
)
|
||||
|
||||
/**
|
||||
|
||||
@@ -401,11 +401,14 @@ private fun ThreatMapCircle(
|
||||
}
|
||||
|
||||
/**
|
||||
* Detection radius, on the main screen because it is the one setting a user
|
||||
* actually reaches for while moving — it decides both what counts as a
|
||||
* detection and how much ground the circle shows. Commits on release rather
|
||||
* than per-pixel so dragging it doesn't restart the location scanners on
|
||||
* every frame.
|
||||
* How far out to look — a view control, not a sensitivity control.
|
||||
*
|
||||
* It sets what the circle draws and what the drill-down lists, and nothing
|
||||
* else: scores come from real distance alone (see ConfidenceEngine's falloff
|
||||
* tables), so widening this adds dots and rows but cannot change the threat
|
||||
* tier. It lives on the main screen because it is the one setting a user
|
||||
* reaches for while actually moving. Commits on release rather than
|
||||
* per-pixel, so dragging doesn't restart the location scanners every frame.
|
||||
*/
|
||||
@Composable
|
||||
private fun RadiusSlider(
|
||||
@@ -420,7 +423,7 @@ private fun RadiusSlider(
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Text(
|
||||
text = "detection radius",
|
||||
text = "show within",
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
fontSize = 11.sp,
|
||||
fontFamily = FontFamily.Monospace
|
||||
|
||||
+4
-4
@@ -53,7 +53,7 @@
|
||||
<div class="container hero-inner">
|
||||
<div class="hero-eyebrow">
|
||||
<span class="dot dot-pulse"></span>
|
||||
v0.5.9 · Android · passive
|
||||
v0.5.10 · Android · passive
|
||||
</div>
|
||||
<h1 class="hero-title">
|
||||
<span class="display-wordmark">OVERWATCH</span>
|
||||
@@ -75,7 +75,7 @@
|
||||
<div class="stat-chip"><span class="num" data-target="6">0</span><span>fused sources</span></div>
|
||||
<div class="stat-chip stat-vfy"><span class="num" data-target="4">0</span><span>threat tiers</span></div>
|
||||
<div class="stat-chip"><span class="num" data-target="0">0</span><span>packets sent</span></div>
|
||||
<div class="stat-chip"><span class="num" data-target="24">0</span><span>releases</span></div>
|
||||
<div class="stat-chip"><span class="num" data-target="25">0</span><span>releases</span></div>
|
||||
</div>
|
||||
|
||||
<div class="cta-row">
|
||||
@@ -432,7 +432,7 @@
|
||||
<ul>
|
||||
<li>Grab the latest debug-signed APK from
|
||||
<a href="https://github.com/KaraZajac/OVERWATCH/releases/latest">Releases</a>
|
||||
(currently <strong>v0.5.9</strong>).</li>
|
||||
(currently <strong>v0.5.10</strong>).</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="tl-col tl-active">
|
||||
@@ -501,7 +501,7 @@
|
||||
transmit, probe, jam, or interfere with any device or network.
|
||||
</p>
|
||||
<p class="footer-meta">
|
||||
v0.5.9 · <a href="https://github.com/KaraZajac/OVERWATCH">github.com/KaraZajac/OVERWATCH</a>
|
||||
v0.5.10 · <a href="https://github.com/KaraZajac/OVERWATCH">github.com/KaraZajac/OVERWATCH</a>
|
||||
</p>
|
||||
<div class="onion-line">
|
||||
<span class="onion-label">Also on Tor</span>
|
||||
|
||||
Reference in New Issue
Block a user