diff options
Diffstat (limited to 'api/debug/report.php')
| -rw-r--r-- | api/debug/report.php | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/api/debug/report.php b/api/debug/report.php index 5625ffe..2ee9c82 100644 --- a/api/debug/report.php +++ b/api/debug/report.php @@ -73,6 +73,65 @@ foreach ($rate as $k => $v) { } save_json(RATE_FILE, $rate); +// ── Network-class filter (2026-10-26) ──────────────────────────────────────────────────────── +// The debug supervisor files an auto report for *any* failed fetch, so a flaky phone connection +// or a retired endpoint becomes a review card. One cluster alone held 14 400 occurrences and +// produced 3 cards. A `Fetch failed:` line is a retry, not a defect: count it and stop. +// Only auto reports whose every error is network-class are filtered — a stack trace, TypeError +// or user-filed report is never dropped here. +define('NET_FILE', DEBUG_DATA_DIR . '/network_failures.json'); +define('NET_KEEP_SOURCES', 40); // bounded: keep the noisiest paths only + +$isNetworkMsg = function ($m) { + return (bool)preg_match( + '/fetch failed|failed to fetch|networkerror|network error|load failed' + . '|the user aborted a request|signal is aborted|err_internet_disconnected|err_network_changed/i', + (string)$m + ); +}; + +if (!empty($diag['auto']) && !empty($diag['errors']) && is_array($diag['errors'])) { + $msgs = []; + foreach ($diag['errors'] as $de) { + if (is_array($de)) $msgs[] = (string)($de['message'] ?? ''); + } + $netCount = count(array_filter($msgs, $isNetworkMsg)); + if ($msgs && $netCount === count($msgs)) { + $day = gmdate('Y-m-d'); + $net = load_json(NET_FILE); + if (!is_array($net) || ($net['day'] ?? '') !== $day) { + $net = ['day' => $day, 'total' => 0, 'filtered_reports' => 0, 'by_source' => []]; + } + $net['total'] = (int)($net['total'] ?? 0) + 1; + $net['filtered_reports'] = (int)($net['filtered_reports'] ?? 0) + 1; + $src = 'unknown'; + foreach (array_merge($msgs, [$title]) as $candidate) { + if (preg_match('~(/[A-Za-z0-9_\-./]+\.(?:php|json))~', (string)$candidate, $m)) { + $src = $m[1]; + break; + } + if (preg_match('~(https?://[^\s]+)~', (string)$candidate, $m)) { + $src = preg_replace('~^https?://[^/]+~', '', $m[1]); + break; + } + } + $net['by_source'][$src] = (int)($net['by_source'][$src] ?? 0) + 1; + if (count($net['by_source']) > NET_KEEP_SOURCES) { + arsort($net['by_source']); + $net['by_source'] = array_slice($net['by_source'], 0, NET_KEEP_SOURCES, true); + } + save_json(NET_FILE, $net); + json_response([ + 'success' => true, + 'filtered' => 'network', + 'source' => $src, + 'day' => $day, + 'count_today' => $net['total'], + 'url' => null, + ], 202); + } +} + // Dedupe: same title + error set + version within 24h collapses onto the existing report. // Hash only the fields the pre-2026-10-23 payload had. Adding `stack` to json_encode($diag['errors']) // would change every fingerprint, so an identical error filed today would not dedupe against the |