Repository navigation
Label volunteer outcomes with the consumer's country - #475
Merged
Merged
Conversation
A producer now reports the ReplyTo of the offer its attempt answered, and Freddie, which remembers the country it derived for each delivered offer, labels freddie.producer.outcomes with consumer_country (CN, IR, RU, US, other, unknown or unreported). That shows whether handshakes that pass ICE and then stall are concentrated in one country, as a DTLS-fingerprinting censor would make them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019DnqgLJf7p4sK87dDvktjx
A connected producer reports its outcome only when its session ends, so a five-minute expiry left long successful sessions unlabeled. Remember offers for a day instead, in insertion order, so expired and evicted entries come off the front rather than a full cache scanning every entry on each offer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019DnqgLJf7p4sK87dDvktjx
Otherwise a producer that reports its attempt before the handler resumes gets consumer_country=unknown. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019DnqgLJf7p4sK87dDvktjx
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
No blocking issues were identified in the cache synchronization, offer correlation lifecycle, bounded labeling, or backward compatibility.
No open issues 🎉
What changed in this PR
Adds a bounded consumer_country label to Freddie’s volunteer outcome metrics, enabling country-level analysis of connection failures without exposing consumer country information to volunteers.
Changes:
- Correlates offers with server-derived countries using a synchronized cache capped at 100,000 entries with a 24-hour expiry.
- Echoes the previous offer ID in producer reports and maps countries to seven fixed label values.
- Adds tests for cache behavior, offer delivery, report lifecycle, and label mapping.
| File | Description |
|---|---|
freddie/outcomes.go |
Adds the consumer country label to outcome metrics. |
freddie/outcomes_test.go |
Updates metric assertions for the new label. |
freddie/offercountry.go |
Implements the bounded, expiring offer-country cache. |
freddie/offercountry_test.go |
Tests expiry, eviction, one-time lookup, and delivery handling. |
freddie/freddie.go |
Initializes the cache and records countries before publishing offers. |
common/outcome.go |
Defines the report field and bounded country mapping. |
common/outcome_test.go |
Tests country label mapping. |
clientcore/producer.go |
Carries the offer ID into the next outcome report. |
clientcore/outcome_test.go |
Tests offer ID reporting and reset behavior. |
Review effort: Balanced
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
freddie.producer.outcomesgets aconsumer_countrylabel: the country of the consumer behind each volunteer attempt. Its values areCN,IR,RU,US,other,unknown, orunreported.Why
About 14% of volunteer attempts end
nat_timeoutwith ICEconnected: STUN got through, then DTLS/SCTP never finished. A censor that fingerprints the DTLS handshake would produce exactly that pattern, as Russia's TSPU did to Snowflake. Snowflake's Go side uses pion, as our consumer does. Freddie currently can't say which country these attempts come from, so it can't tell a censor from a slow network.How
Freddie already derives each consumer's country server-side (
Freddie.ConsumerCountry, from the CDN front's headers, used for genesis targeting). It knows the country for over 99.9% of consumer requests. This PR links that country to the volunteer's report:freddie/freddie.go:freddie/offercountry.go: the cache.unknown.clientcore/producer.go: the producer already receives that request ID as the offer'sReplyTo. It now echoes it back on its next genesis asprev-offer-id.freddie/outcomes.go: Freddie looks the ID up once and labels the outcome.common/outcome.go: the new field, and the mapping onto the bounded label.Privacy: the producer only sends back an ID that Freddie created and already handed it. Freddie learns nothing it didn't have, and the volunteer learns nothing about the consumer. The country label is limited to four named countries plus
other.Rollout:
unreporteduntil their tabs reload.unreporteduntil a Lantern release includes this.Side effect in lantern-cloud: lantern-cloud's
ConsumerCountryhook incrementsfreddie.consumer_countryon each call. Offer POSTs now add to that count. That's a few hundred calls an hour against roughly 8M subscribes an hour, so negligible.Testing
go test -race ./common/ ./clientcore/ ./freddie/: ok. New tests cover:ruconsumer gives the volunteer's outcomeRU; a second report of the same offer givesunknown; an undelivered offer isn't cached.GOOS=js GOARCH=wasm go build ./cmd: ok.freddie.producer.outcomesbyconsumer_country.Risk
Low. Freddie holds at most 100k small entries, and signaling behavior is unchanged. The riskiest file is
freddie/freddie.go, which now calls the country hook on offer POSTs as well as subscribes.How to revert
Revert the merge commit, and bump broflake in lantern-cloud again.
Pre-PR review (local Codex gate)
CODEX GATE: verdict=approve critical=0 important=0 minor=0 preexisting=0 reviewed=93f9f6cbapprovefreddie/offercountry.go:12— the 5-minute expiry left long connected sessions unlabeled, since they report only when the session ends. Now 24 h. (r1)freddie/offercountry.go— a full cache scanned every entry on each add. Now insertion-ordered and O(1). (Flagged by the automated security review on r1's commit.)freddie/freddie.go:841— the country was cached after the offer was published, so a fast report could miss it. Now cached first. (r2)AGENTS.mdadditions: none🤖 Generated with Claude Code
https://claude.ai/code/session_019DnqgLJf7p4sK87dDvktjx
Summary by CodeRabbit