Method
How Rivulet gets from a photo to a status
Rivulet is a trust and quality layer for citizen observations. This page states every step, every constant and what the result does not mean, so a scientist can disagree with it precisely. Method version 1.5.0, published 2026-09-21.
Rules, not a black box: no learned model decides a status. The one AI component only flags a photo for a person to look at.
The pipeline
1. Read the colour
The phone photo is reduced on the device to a water colour on the 21-step Forel–Ule scale, using a simplified WACODI-style conversion (sRGB to CIE XYZ to hue angle). The full photo never leaves the phone: only the class, a confidence and, for the optional photo check, a tiny thumbnail are sent. There is no per-camera calibration, so colour is a proxy, not a measurement.
src/lib/science/forel-ule.ts, extract-colour.ts
2. Turn what people see into evidence
Smell, foam, algae, dead fish, clarity, flow, litter and recognisable animal groups each add a small, declared amount of evidence for or against good condition. Animal groups use sensitivity values on the BMWP 1–10 family scale as a simplified proxy, not the BMWP protocol.
src/lib/science/indicators.ts
3. Check before counting
GPS accuracy, distance from the mapped stream, an hourly limit per observer and an optional AI check that the photo shows water are evaluated independently. Anything doubtful is stored but held out of assessments, trust and exports until a person approves or rejects it.
src/lib/science/plausibility.ts, src/lib/moderation/
4. Weigh the observer
Each observer's trust is how well they agree with other people's reports of the same streams (leave-one-out, so nobody is judged against themselves), shrunk toward neutral when there is little history. Trust multiplies the weight of their evidence. Agreement is not truth: observers who agree can all be wrong.
src/lib/science/trust.ts, weighting.ts
5. Estimate with uncertainty
Weighted evidence updates a Beta–Bernoulli posterior. Rivulet reports its mean, a 90% credible interval and a data-confidence figure. Below a minimum confidence it says "insufficient data" instead of guessing. Five status classes carry the names of the EU Water Framework Directive, but their limits are equal-width priors, so this is not an official classification.
src/lib/science/bayes.ts, wfd.ts, snapshot.ts
6. Read it for people and animals
Hazard is the trust-weighted share of recent reports showing a warning sign. Exposure is what OpenStreetMap places within 150 m: playgrounds, schools, parks, dog areas, bathing and fishing spots. A hazard near a place people or dogs use raises the concern. No recent reports reads as unknown, never as safe.
src/lib/science/one-health.ts
7. Cross-check from space
A Sentinel-2 hue angle for the stream is compared with the residents' colour. Most urban streams are narrower than a 10 m pixel, so most get no clear satellite view. If the two disagree beyond a declared threshold, every contributing weight is halved: the estimate widens and confidence cannot rise because of that pass. The reflectance conversion is a placeholder, not the published Sentinel-2 calibration.
src/lib/science/satellite.ts, scripts/satellite/
Every constant, declared
80 parameters: 8 come from a cited standard or publication and 72 are expert-judgement priors that say, in their own row, that they are uncalibrated and why they were chosen. Nothing is an unlabelled magic number. The list below is generated from the code's own registry, so it cannot drift from what runs.
Water colour scale5
forel-ule.class-limits21 valuesStandard
Hue angle class limits: Novoa, Wernand & van der Woerd 2013, J. Eur. Opt. Soc. Rapid Publ. 8, 13057 (doi:10.2971/jeos.2013.13057), as distributed in CefasRepRes/FUME data/hue_angle_limits_NWW2013.csv; legend colours from FUME forelulecmap(). FUME contains public sector information licensed under the Open Government Licence v3.0. Hue angle measured from chromaticity x = y = 1/3.
forel-ule.hue-reference0.3333, 0.3333Standard
Forel–Ule hue angle convention, chromaticity x = y = 1/3 (Novoa, Wernand & van der Woerd 2013; as implemented in CefasRepRes/FUME)
forel-ule.min-usable-pixels100Prior
Below this many coloured open-water pixels the mean hue is dominated by glare, banks and noise, so no reading is returned. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
forel-ule.min-chroma-distance0.01Prior
Pixels this close to the D65 white point (sky glare, foam, overcast reflections) carry no water hue and would bias readings toward blue-green classes, so they are excluded. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
forel-ule.confidence-spread-scale30Prior
A circular hue spread of this many degrees across the sampled region maps to zero confidence, falling linearly from full confidence at zero spread. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
Colour conversion3
colour.srgb-transfer0.0404, 12.92, 0.055, 2.4Standard
IEC 61966-2-1:1999, sRGB colour space transfer function
colour.srgb-to-xyz0.4125, 0.3576, 0.1804, 0.2127, 0.7152, 0.0722, 0.0193, 0.1192, 0.9503Standard
IEC 61966-2-1:1999, linear sRGB (D65) to CIE 1931 XYZ matrix
colour.d65-white0.3127, 0.329Standard
CIE standard illuminant D65 chromaticity, CIE 1931 2° standard observer
indicators17
indicators.bmwp-max-score10Standard
Maximum family score of the Biological Monitoring Working Party score system (Armitage, Moss, Wright & Furse 1983, Water Research 17:333–347)
indicators.taxon-sensitivity10, 9, 8, 6, 3, 1Prior
Sensitivity for the taxon groups a resident can recognise (stonefly, mayfly, caddisfly, freshwater shrimp, leech, sludge worm), set on the 1–10 BMWP family scale (Armitage et al. 1983). Mayfly and caddisfly groups contain families with a wide range of BMWP scores, so single representative values are used. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
indicators.evidence.sensitiveTaxonThreshold6Prior
Taxa scoring at or above this BMWP-scale value count as evidence of good condition; below it, as evidence of organic pollution. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
indicators.evidence.forelUleClearMax5Prior
Forel–Ule classes up to this value (blue to greenish-blue water) count as evidence of low algal enrichment. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
indicators.evidence.forelUleEnrichedMin13Prior
Forel–Ule classes from this value (yellowish-green to brown water) count as evidence of enrichment or heavy humic and sediment load. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
indicators.evidence.forelUleClear1Prior
Evidence added for a clear-water Forel–Ule class. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
indicators.evidence.forelUleEnriched1Prior
Evidence added for an enriched Forel–Ule class. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
indicators.evidence.forelUleIntermediate0.25Prior
Weak positive evidence for intermediate Forel–Ule classes, which are common in healthy lowland streams. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
indicators.evidence.pollutedOdour1.5Prior
Sewage or chemical odour is treated as strong evidence of contamination. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
indicators.evidence.foam0.5Prior
Persistent surface foam is treated as moderate evidence of detergents or organic load. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
indicators.evidence.deadFish2Prior
Dead fish are treated as the strongest single survey signal of acute pollution or oxygen depletion. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
indicators.evidence.visibleAlgae0.75Prior
Visible algal growth is treated as evidence of nutrient enrichment. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
indicators.evidence.stagnantFlow0.5Prior
Stagnant flow is treated as mild evidence of degraded condition through low oxygen and warming. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
indicators.evidence.heavyLitterMin2Prior
Litter levels from this value on the 0–3 survey scale count as heavy. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
indicators.evidence.heavyLitter0.5Prior
Evidence added for heavy litter on the margins. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
indicators.evidence.clearWater0.5Prior
Evidence added when the resident reports clear water. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
indicators.evidence.opaqueWater1Prior
Evidence added when the resident reports opaque water. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
Observation weighting12
weighting.base0.5Prior
Starting weight of an observation before evidence-quality adjustments. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
weighting.photoBonus0.2Prior
Largest weight added when a photo yields a Forel–Ule reading, scaled by that reading's confidence. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
weighting.unknownPhotoConfidence0.5Prior
Colour confidence assumed for a photo whose reading confidence is unknown. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
weighting.measurementBonus0.05Prior
Weight added for each instrument reading (pH, dissolved oxygen, temperature, nitrate). Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
weighting.maxCountedMeasurements4Prior
Instrument readings beyond this count add no further weight. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
weighting.preciseGpsMetres20Prior
GPS accuracy at or better than this many metres carries no penalty. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
weighting.approximateGpsMetres100Prior
GPS accuracy up to this many metres counts as approximate. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
weighting.approximateGpsFactor0.85Prior
Weight multiplier for an approximate GPS position. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
weighting.poorGpsFactor0.6Prior
Weight multiplier for a poor or unknown GPS position. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
weighting.unknownGpsMetres1000Prior
Accuracy assumed when the device reports none, so unknown precision is treated as poor rather than good. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
weighting.halfLifeHours720Prior
An observation's weight halves after this many hours (30 days), reflecting how quickly stream condition can change. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
weighting.floor0.1Prior
Minimum weight, so no accepted observation is silently discarded. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
Bayesian estimate2
bayes.uniform-prior1, 1Standard
Bayes–Laplace uniform prior Beta(1, 1) for a proportion with no prior information (Gelman et al., Bayesian Data Analysis, 3rd ed., 2013, chapter 2)
bayes.credible-mass0.9Prior
Probability mass of the reported equal-tailed credible interval; a reporting convention chosen for Rivulet v1. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
confidence6
confidence.volumeScale5Prior
Effective observation weight at which the volume component reaches about 63% of its maximum. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
confidence.diversityScale3Prior
Number of distinct observers at which the diversity component reaches about 63% of its maximum. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
confidence.recencyHalfLifeHours1440Prior
The recency component halves after this many hours (60 days) since the newest observation. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
confidence.volumeWeight0.4Prior
Share of data confidence given to the amount of weighted evidence. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
confidence.diversityWeight0.3Prior
Share of data confidence given to the number of independent observers. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
confidence.recencyWeight0.3Prior
Share of data confidence given to how recent the newest observation is. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
Status classes2
wfd.class-boundaries0.2, 0.4, 0.6, 0.8Prior
Directive 2000/60/EC (Annex V) defines five ecological status classes on an Ecological Quality Ratio from 0 to 1, but sets class boundaries per quality element through intercalibration; Rivulet v1 uses equal-width bands with boundaries at 0.2, 0.4, 0.6 and 0.8. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
wfd.min-confidence-for-class0.25Prior
Below this data confidence no ecological status class is assigned and the stream is shown as having insufficient data. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
Observer trust5
trust.priorStrength5Prior
Pseudo-count weight of the neutral prior against an observer's own agreement evidence, in units of observations. Trust is shrunk towards this neutral value using a Beta-binomial-style pseudo-count prior (Gelman et al., Bayesian Data Analysis, 3rd ed., 2013, chapter 5). Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
trust.minIndependent2Prior
An observation gives no trust signal unless at least this many observations by other observers exist for the same water body. Trust is shrunk towards this neutral value using a Beta-binomial-style pseudo-count prior (Gelman et al., Bayesian Data Analysis, 3rd ed., 2013, chapter 5). Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
trust.multiplierMin0.4Prior
Lower clamp on the trust multiplier applied to evidence weight. Trust is shrunk towards this neutral value using a Beta-binomial-style pseudo-count prior (Gelman et al., Bayesian Data Analysis, 3rd ed., 2013, chapter 5). Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
trust.multiplierMax1.6Prior
Upper clamp on the trust multiplier applied to evidence weight. Trust is shrunk towards this neutral value using a Beta-binomial-style pseudo-count prior (Gelman et al., Bayesian Data Analysis, 3rd ed., 2013, chapter 5). Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
trust.neutralTrust0.5Prior
Trust score with no effect on evidence weight (multiplier of 1). Trust is shrunk towards this neutral value using a Beta-binomial-style pseudo-count prior (Gelman et al., Bayesian Data Analysis, 3rd ed., 2013, chapter 5). Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
Plausibility checks5
plausibility.maxGpsAccuracyM250Prior
GPS accuracy worse than this many metres (or missing) flags the observation for human review instead of auto-approving it. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
plausibility.maxPerHour5Prior
More than this many observations by the same observer in the previous hour flags the batch for human review as a basic anti-spam check. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
plausibility.maxFutureMinutes5Prior
A claimed observation time more than this many minutes ahead of the server clock is rejected outright as an implausible payload. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
plausibility.maxPastDays30Prior
A claimed observation time more than this many days behind the server clock is rejected outright as an implausible payload. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
plausibility.maxDistanceFromWaterbodyM200Prior
A submitted GPS point more than this many metres from the claimed water body's geometry flags the observation for human review instead of auto-approving it, but never blocks submission. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
Points4
contribution.basePoints10Prior
Points awarded for one counted, trust- and quality-weighted observation. This is a programme rule, not a scientific estimate, but is declared here for transparency. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
contribution.gapBonus5Prior
Extra points for the first observation on a water body that had none in the preceding window, rewarding coverage over repetition. This is a programme rule, not a scientific estimate, but is declared here for transparency. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
contribution.gapDays30Prior
A water body counts as a data gap if it had no observation in this many preceding days. This is a programme rule, not a scientific estimate, but is declared here for transparency. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
contribution.minTrustForPoints0.35Prior
Below this Trust Score an observer earns no points, so sheer volume of readings that disagree with everyone else cannot buy a place in the ranking. This is a programme rule, not a scientific estimate, but is declared here for transparency. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
Certificates5
certificate.contributorMinObservations5Prior
Validated observations required for the entry-level Contributor certificate. This is a programme rule, not a scientific estimate, but is declared here for transparency. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
certificate.contributorMinTrust0.5Prior
Minimum Trust Score required for the Contributor certificate. This is a programme rule, not a scientific estimate, but is declared here for transparency. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
certificate.dataStewardMinObservations20Prior
Validated observations required for the higher Data Steward certificate. This is a programme rule, not a scientific estimate, but is declared here for transparency. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
certificate.dataStewardMinTrust0.6Prior
Minimum Trust Score required for the Data Steward certificate. This is a programme rule, not a scientific estimate, but is declared here for transparency. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
certificate.dataStewardMaxRank100Prior
Rank an observer must reach or beat in their home city's people leaderboard for the Data Steward certificate. This is a programme rule, not a scientific estimate, but is declared here for transparency. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
oneHealth6
oneHealth.windowDays30Prior
Only observations from this many recent days count as current hazard signs; older reports say little about the water today, and no recent report is shown as unknown, never as safe. An indicative screening rule, not a public health or bathing-water assessment. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
oneHealth.exposureRadiusM150Prior
Playgrounds, schools, parks, bathing and fishing spots and allotments within this distance of a stream count as bringing people or dogs close to it. An indicative screening rule, not a public health or bathing-water assessment. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
oneHealth.possibleShare0.2Prior
A sign (sewage smell, algae or scum, chemical smell or foam, dead fish, heavy litter) counts as a possible hazard when at least this trust- and quality-weighted share of recent reports mention it. An indicative screening rule, not a public health or bathing-water assessment. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
oneHealth.likelyShare0.5Prior
A sign counts as a likely hazard when at least this weighted share of recent reports mention it. An indicative screening rule, not a public health or bathing-water assessment. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
oneHealth.likelyMinObservers2Prior
A likely hazard also needs this many different observers, so one person cannot raise a stream to the highest concern alone. An indicative screening rule, not a public health or bathing-water assessment. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
oneHealth.heavyLitterMin2Prior
Litter at or above this value on the 0–3 survey scale counts as an injury hazard for children, dogs and wildlife. An indicative screening rule, not a public health or bathing-water assessment. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
Satellite cross-check8
satellite.minUsablePixels4Prior
Below this many cloud-, shadow- and land-masked water pixels in the sample window, a Sentinel-2 pass is recorded with null indices rather than a reading — never as agreement. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
satellite.minNdwi0Prior
A pixel counts as open water if its NDWI is above this value or the Sentinel-2 scene classification labels it water (class 6); other pixels are treated as land or mixed bank and excluded from the mean. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
satellite.windowPixels5Prior
Width in 10 m pixels of the band sampled along each water body's whole line; urban streams are narrower than a pixel, so most are invisible to Sentinel-2 and are recorded as unavailable rather than guessed. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
satellite.maxAgeDays30Prior
A satellite reading older than this many days no longer counts as a current cross-check and is excluded from the snapshot. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
satellite.evidenceWeight0.4Prior
Weight a satellite reading carries in the Bayesian model relative to a full-weight citizen observation, reflecting its coarser spatial resolution and unvalidated calibration. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
satellite.divergenceThresholdFu3Prior
Absolute Forel-Ule class distance between the citizen and satellite readings above which they are treated as diverging rather than agreeing. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
satellite.cie-band-centre-cmf0.032, 0.208, 0.4652, 0.5945, 0.995, 0.0039, 0.1212, 0.0446, 0Standard
CIE 1931 2° standard observer colour-matching functions (CIE 15:2004), read at the 5nm-tabulated wavelength nearest each Sentinel-2 L2A band's centre wavelength (blue B02 ≈492nm, green B03 ≈560nm, red B04 ≈665nm)
satellite.hue-angle-calibration0Prior
The Sentinel-2 hue-angle conversion (reflectance -> CIE XYZ via band-centre colour-matching weights -> hue angle) is a placeholder approximation, NOT the published van der Woerd & Wernand (2015, 2018) Sentinel-2 hue-angle calibration and its delta-correction, which Rivulet intends to adopt once implemented. Treat satellite Forel-Ule equivalents as a coarse, uncalibrated cross-check rather than a validated measurement. Uncalibrated Rivulet v1 expert-judgement prior; calibration against official water-quality data is planned.
How the model behaves
The engine's own answers to fixed, simple situations, computed live rather than described. Each report is from a different observer at neutral trust unless stated. Read the interval, not just the class: one report already gives a class, but with a wide interval, and the interval narrows as reports agree.
Agreeing reports
| Situation | Mean | 90% interval | Confidence | Status |
|---|---|---|---|---|
| No reports (0) | 0.50 | 0.05–0.95 | 0.00 | insufficient data |
| All healthy (1) | 0.81 | 0.51–0.99 | 0.46 | high |
| All healthy (2) | 0.89 | 0.68–0.99 | 0.58 | high |
| All healthy (3) | 0.92 | 0.77–1.00 | 0.67 | high |
| All healthy (5) | 0.95 | 0.85–1.00 | 0.80 | high |
| All healthy (8) | 0.97 | 0.90–1.00 | 0.90 | high |
| All healthy (12) | 0.98 | 0.93–1.00 | 0.96 | high |
| All polluted (1) | 0.14 | 0.01–0.38 | 0.46 | bad |
| All polluted (2) | 0.08 | 0.00–0.23 | 0.58 | bad |
| All polluted (3) | 0.06 | 0.00–0.16 | 0.67 | bad |
| All polluted (5) | 0.03 | 0.00–0.10 | 0.80 | bad |
| All polluted (8) | 0.02 | 0.00–0.07 | 0.90 | bad |
| All polluted (12) | 0.02 | 0.00–0.04 | 0.96 | bad |
Disagreeing reports
| Situation | Mean | 90% interval | Confidence | Status |
|---|---|---|---|---|
| Half healthy, half polluted (4) | 0.40 | 0.23–0.58 | 0.74 | poor |
| Half healthy, half polluted (8) | 0.39 | 0.27–0.53 | 0.90 | poor |
| Half healthy, half polluted (12) | 0.39 | 0.29–0.50 | 0.96 | poor |
Whom you believe
| Situation | Mean | 90% interval | Confidence | Status |
|---|---|---|---|---|
| 3 healthy from trusted observers, 3 polluted from low-trust | 0.70 | 0.54–0.84 | 0.84 | good |
| 3 healthy from low-trust observers, 3 polluted from trusted | 0.16 | 0.07–0.28 | 0.84 | bad |
The last table is the point of the trust layer: the same six reports give a different answer depending on who made them, because an observer who has tended to disagree with everyone else counts for less. Mixed evidence lands below the middle because warning signs are weighted more heavily than the absence of them, a declared choice.
What it does not claim
- It is not a laboratory, regulatory or public-health assessment, and never says water is safe.
- The class names come from Directive 2000/60/EC Annex V; the class limits are not calibrated EQR boundaries.
- Colour comes from an uncalibrated phone camera and says nothing about chemistry.
- Trust is peer agreement, not truth, and the model still needs validating against independent measurements.
- The satellite check is coarse and its reflectance conversion is a declared placeholder.
- Rivulet's survey is a quick visual complement to, not a substitute for, the professional OneAquaHealth field sampling protocols (macroinvertebrates, water chemistry, habitat and more).
Version history
- 1.5.0 — Resident-scored flow and the animal-group score no longer borrow the OneAquaHealth codes hydrology and macroinvertebreates: they move to the Rivulet code system as flow-state and invertebrate-groups-score, because a resident's 0-3 flow rating and a BMWP-family sum are not a hydromorphological survey or a benthic macroinvertebrate count. No estimate changes. Each exported Observation also carries the stated derivation of its value as a note.
- 1.4.0 — Sentinel-2 satellite readings enter computeSnapshot as an independent, coarse cross-check at a fixed evidence weight. The reflectance-to-hue-angle conversion uses CIE 1931 colour-matching weights at each band's centre wavelength and is NOT the published van der Woerd & Wernand Sentinel-2 hue-angle calibration (see satellite.hue-angle-calibration). When the citizen and satellite Forel-Ule readings diverge beyond the declared threshold, every contributing weight for that water body is halved: the posterior widens and data confidence cannot rise because of the diverging pass.
- 1.3.0 — One Health reading: warning signs from the last 30 days of trust-weighted reports (hazard) combined with playgrounds, schools, parks, bathing and fishing spots and allotments from OpenStreetMap within 150 m (exposure), shown for people, dogs and wildlife. No recent reports reads as unknown, never as safe.
- 1.2.0 — Observations flagged by plausibility checks no longer count towards assessments, trust or exports until a person reviews them. Resident-reported signs (clarity, sewage odour, algae, foam, dead fish, litter) move from OneAquaHealth analyte codes to the Rivulet code system. Flow and litter are now asked in the survey instead of defaulting.
- 1.1.0 — Observer trust now weights evidence: computeSnapshot multiplies each observation's quality weight by trustMultiplier(observerTrust), shrinking noisy or disagreeing observers' influence towards neutral.
Sources
- Directive 2000/60/EC of the European Parliament and of the Council establishing a framework for Community action in the field of water policy (Water Framework Directive), Annex V
- Novoa, Wernand & van der Woerd 2013, The Forel-Ule scale revisited spectrally: preparation protocol, transmission measurements and chromaticity, J. Eur. Opt. Soc. Rapid Publ. 8, 13057 (hue angle class limits via CefasRepRes/FUME)
- Novoa et al. 2015, WACODI: a generic algorithm to derive the intrinsic color of natural waters from digital images, Limnology and Oceanography: Methods, doi:10.1002/lom3.10059
- IEC 61966-2-1:1999, Multimedia systems and equipment — Colour measurement and management — Default RGB colour space — sRGB
- Armitage, Moss, Wright & Furse 1983, The performance of a new biological water quality score system based on macroinvertebrates over a wide range of unpolluted running-water sites, Water Research 17:333-347
- Gelman et al. 2013, Bayesian Data Analysis, 3rd edition, CRC Press
- Gelman et al. 2013, Bayesian Data Analysis, 3rd edition, CRC Press, chapter 5 (hierarchical and shrinkage models — basis for shrinking observer trust towards neutral)
- HL7 Europe, OneAquaHealth FHIR Implementation Guide, github.com/hl7-eu/oah
- van der Woerd, H.J. & Wernand, M.R. 2015, True Colour Classification of Natural Waters with Medium-Spectral Resolution Satellites: SeaWiFS, MODIS, MERIS and OLCI, Sensors 15(10):25663-25680, doi:10.3390/s151025663 — intended Sentinel-2 hue-angle calibration, not yet adopted
- van der Woerd, H.J. & Wernand, M.R. 2018, Hue-Angle Product for Low to Medium Spatial Resolution Optical Satellite Sensors, Remote Sensing 10(2):180, doi:10.3390/rs10020180 — Sentinel-2 delta-correction, not yet adopted
- Copernicus Sentinel data 2026, processed via Element 84 Earth Search STAC and AWS-hosted Sentinel-2 L2A Cloud-Optimised GeoTIFFs
The code is open under Apache-2.0 and its tests are in src/lib/science. Data leaves Rivulet as FHIR from the open data page.