Walks Entry[] once and emits one ErrorContextProblem per ERROR or
WARNING entry, attaching up to 20 entries before and 20 after as
context. Overlapping windows clip the second hit's before- and
after-ranges so no Entry appears in two context arrays. Caps emission
at 500 hits and adds an ErrorContextTruncatedInformation when reached.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Compares consecutive perks-snapshot rows per Steam ID and emits a
SkillProgressionAnomalyProblem for any single skill whose level gained
more than THRESHOLD_DELTA between two snapshots. Login/Logout/LevelUp
event rows are skipped via a perk-pair regex check on the bracketed
event field.
Threshold of 3 reflects PZ's slow leveling pace: typical session bridges
should not produce four-or-more level jumps in a single skill. The
constant is documented inline so operators can tune for modded XP
servers without touching analysis logic.
Synthetic fixture extended with a PlayerSuspect Steam ID carrying two
snapshots: Strength jumps 2 -> 10 (delta +8, triggers), Fitness jumps
2 -> 8 (+6, triggers), Maintenance jumps 0 -> 3 (+3, exactly at
threshold, does NOT trigger). The existing single-snapshot players
remain noise-free.
Sliding-window heuristic over (Steam ID, item code) groups: any window of
THRESHOLD_WINDOW_SECONDS containing THRESHOLD_COUNT or more positive-delta
events for the same player/item pair triggers a Problem. Negative deltas
(drops, transfers out) are filtered. Five events in ten seconds (defaults)
encodes the rule of thumb that legitimate gameplay rarely produces five
identical items in that span.
Constants live as class constants on the analyser so operators can
override via subclass without touching analysis logic; the docblocks
record the justification.
Synthetic fixture extended with a 6-event burst (AdminUser +
Base.Bullets9mm in <1s) and a 4-event sub-threshold group (Player1 +
Base.Plank scattered over 4 minutes) to exercise both paths.
First custom Analyser subclass in this game tree. PatternAnalyser
operates per-entry without cross-entry state, so pairing
'attempting to join' with 'allowed to join' per Steam ID requires a
bespoke pass over the log. The analyser counts attempts and allowed
events per Steam ID and emits a ConnectionFailureProblem for each
player whose attempt count exceeds their allowed count. Unmatched
'attempting to join used queue' rows are surfaced as failures in v1
because a long queue wait is indistinguishable from a real failure
without timing context.
Bulk substitution across all PHP files in src/ and test/. Covers
namespace declarations, use statements, fully-qualified class
references, and @package PHPDoc tags. No logic changes.