Types the spec asks for beyond the payment card itself: settlement
account (20 digits), BIK, card expiry date (kept separate from
birth date), OGRN/OGRNIP (negative lookahead so OGRNIP isn't half-
swallowed by the OGRN rule), KPP, income/salary amounts, and mentions
of biometric enrollment (ЕБС, voice/fingerprint templates).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Same reasoning as the existing CVV/PIN/DATE entries: a bare mention
("Экскурсия в Нижний Новгород", "цены выросли в Казахстане") isn't
personal data on its own, only alongside some other PD that ties it to
a specific person. The mechanism was already generic — this only adds
two more types to the default set.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds current public figures (Nabiullina, Gref, Putin, ...) so news-
style mentions near CB/banking topics aren't treated as client PII.
More importantly, isWellKnown() only worked for consonant-ending
surnames: "Пушкина" starts with "Пушкин" so it matched, but "Толстого"
doesn't start with "Толстой" (adjectival declension replaces the
ending, doesn't extend it), and neither does any oblique case of a
feminine -a surname ("Набиуллиной" vs "Набиуллина"). Strips the
trailing vowel at load time, same trick already used for given names.
Also lets the list grow without a rebuild: an optional external file
(pdguard.well-known-file, default config/well-known.txt) is merged on
top of the bundled list and re-read on change, mirroring how
SystemsConfig watches systems.json.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The rule matched any capitalized word after "г."/"город" — no check
that it's an actual place. ToponymDictionary checks the match against
1111 Russian cities (pensnarik/russian-cities) plus CIS capitals,
matching by stem so declined forms work ("Москве" against "Москва").
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Under 0.5-CPU containers, a static Semaphore(2000) never tripped —
latency ballooned to 1.5-2s instead of the service answering 429.
Runtime.availableProcessors() can't help pick a number either: it
ignores the cgroups --cpus quota and reports full host cores.
AdaptiveConcurrencyLimiter reacts to observed latency instead of
guessing capacity: starts at min-concurrent, grows by one per
adjustment window when latency stays under target, halves it the
moment it doesn't. Adjustment is gated by wall-clock time, not by
request count — an earlier per-request version let the limit race to
the ceiling in milliseconds under high RPS, before any real overload
had a chance to show up in the samples.
Verified under load (native image, 250MB/0.5 CPU): p50 latency at 3x
overload dropped from ~1.3s to under 4ms; normal-load p95 unaffected.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>