muaddib-scanner 2.11.78 → 2.11.80
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
package/src/monitor/state.js
CHANGED
|
@@ -1115,6 +1115,12 @@ function computeLedgerRollup(sinceTs, opts = {}) {
|
|
|
1115
1115
|
const scannedKeys = new Set();
|
|
1116
1116
|
const droppedKeys = new Set();
|
|
1117
1117
|
let exactVanished = true;
|
|
1118
|
+
// Distinct package NAMES (version-collapsed) for honest coverage. A package is
|
|
1119
|
+
// "covered" if at least one of its versions reached a real scan (non-dropped).
|
|
1120
|
+
// Bounded: names are only added while underCap, so |names| ≤ |keys| ≤ MAX_ROLLUP_KEYS.
|
|
1121
|
+
// Exactness mirrors exactVanished (false iff the cap was hit mid-window).
|
|
1122
|
+
const allNames = new Set();
|
|
1123
|
+
const scannedNames = new Set();
|
|
1118
1124
|
|
|
1119
1125
|
_iterateJsonlSync(file, (e) => {
|
|
1120
1126
|
if (!e || !e.name) return;
|
|
@@ -1140,11 +1146,11 @@ function computeLedgerRollup(sinceTs, opts = {}) {
|
|
|
1140
1146
|
const underCap = exactVanished && (scannedKeys.size + droppedKeys.size) < MAX_ROLLUP_KEYS;
|
|
1141
1147
|
if (outcome === 'dropped') {
|
|
1142
1148
|
dropped++; ecoNode.dropped++;
|
|
1143
|
-
if (underCap) droppedKeys.add(key); else exactVanished = false;
|
|
1149
|
+
if (underCap) { droppedKeys.add(key); allNames.add(e.name); } else exactVanished = false;
|
|
1144
1150
|
} else {
|
|
1145
1151
|
scanned++; ecoNode.scanned++;
|
|
1146
1152
|
if (outcome === 'suspect' || outcome === 'confirmed') { alerted++; ecoNode.alerted++; }
|
|
1147
|
-
if (underCap) scannedKeys.add(key); else exactVanished = false;
|
|
1153
|
+
if (underCap) { scannedKeys.add(key); allNames.add(e.name); scannedNames.add(e.name); } else exactVanished = false;
|
|
1148
1154
|
}
|
|
1149
1155
|
});
|
|
1150
1156
|
|
|
@@ -1164,6 +1170,13 @@ function computeLedgerRollup(sinceTs, opts = {}) {
|
|
|
1164
1170
|
alerted,
|
|
1165
1171
|
// NOT a TPR — see the HONEST METRIC NOTE above. null when nothing was scanned.
|
|
1166
1172
|
alertRate: scanned > 0 ? alerted / scanned : null,
|
|
1173
|
+
// Honest, version-collapsed coverage: distinct package names seen vs scanned.
|
|
1174
|
+
// Bounded ≤100% by construction (scannedNames ⊆ allNames). Unlike the raw
|
|
1175
|
+
// event-count coverage in the embed, this is immune to version-spam inflation
|
|
1176
|
+
// (e.g. a package publishing thousands of versions counts once).
|
|
1177
|
+
distinctPackages: allNames.size,
|
|
1178
|
+
distinctScanned: scannedNames.size,
|
|
1179
|
+
distinctCoverage: allNames.size > 0 ? scannedNames.size / allNames.size : null,
|
|
1167
1180
|
byOutcome,
|
|
1168
1181
|
byEcosystem
|
|
1169
1182
|
};
|
package/src/monitor/webhook.js
CHANGED
|
@@ -1027,25 +1027,41 @@ function buildDailyReportEmbed(stats, dailyAlerts, ledgerRollup) {
|
|
|
1027
1027
|
// Avg scan time from in-memory stats
|
|
1028
1028
|
const avg = stats.scanned > 0 ? (stats.totalTimeMs / stats.scanned / 1000).toFixed(1) : '0.0';
|
|
1029
1029
|
|
|
1030
|
-
// --- Coverage
|
|
1031
|
-
//
|
|
1032
|
-
//
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
//
|
|
1036
|
-
//
|
|
1030
|
+
// --- Phase 0b: per-scan ledger rollup (resolved early so Coverage can use it) ---
|
|
1031
|
+
// Caller may pass a precomputed rollup (sendDailyReport does, to persist the same
|
|
1032
|
+
// numbers it displays); undefined → compute here; explicit null → omit the section.
|
|
1033
|
+
const ledger = ledgerRollup !== undefined ? ledgerRollup : safeLedgerRollup();
|
|
1034
|
+
|
|
1035
|
+
// --- Coverage ---
|
|
1036
|
+
// HEADLINE: honest, version-collapsed coverage from the scan-ledger — distinct
|
|
1037
|
+
// package NAMES actually scanned vs distinct names seen (scanned + dropped) in
|
|
1038
|
+
// the window. Bounded ≤100% by construction and immune to version-spam (a
|
|
1039
|
+
// package publishing thousands of versions counts once). The raw publish-event
|
|
1040
|
+
// ratio is kept as a SECONDARY line for continuity but is no longer the headline:
|
|
1041
|
+
// it races re-scans / PyPI / burst extras against an npm-only event denominator
|
|
1042
|
+
// and routinely exceeds 100% (see AUDIT 4 — daily-reports-analysis.md).
|
|
1037
1043
|
const attempted = stats.uniqueScanAttempts || 0;
|
|
1038
1044
|
const npmPub = stats.npmPublishEventsSeen || 0;
|
|
1039
1045
|
const pypiPub = stats.pypiChangelogPackages || 0;
|
|
1040
1046
|
const published = npmPub + pypiPub;
|
|
1041
|
-
const coverageRatio = published > 0 ? (attempted / published * 100).toFixed(0) : '0';
|
|
1042
1047
|
const catchupSkipped = (stats.npmCatchupSkippedSeqs || 0) + (stats.pypiCatchupSkippedEvents || 0);
|
|
1043
1048
|
const opsSuffix = catchupSkipped > 0
|
|
1044
1049
|
? `\nOps: ${stats.scanned} | Catch-up skip: ${catchupSkipped}`
|
|
1045
1050
|
: `\nOps: ${stats.scanned}`;
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1051
|
+
let coverageText;
|
|
1052
|
+
if (ledger && ledger.distinctPackages > 0 && ledger.distinctCoverage != null) {
|
|
1053
|
+
const pct = (ledger.distinctCoverage * 100).toFixed(0);
|
|
1054
|
+
const approx = ledger.exactVanished === false ? '~' : '';
|
|
1055
|
+
coverageText = `${ledger.distinctScanned}/${ledger.distinctPackages} pkgs (${approx}${pct}%)`;
|
|
1056
|
+
if (published > 0) coverageText += `\nRaw events: ${attempted}/${published}`;
|
|
1057
|
+
coverageText += opsSuffix;
|
|
1058
|
+
} else if (published > 0) {
|
|
1059
|
+
// Fallback: ledger unavailable (first boot / empty ledger) → legacy event ratio.
|
|
1060
|
+
const coverageRatio = (attempted / published * 100).toFixed(0);
|
|
1061
|
+
coverageText = `${attempted}/${published} (${coverageRatio}%)${opsSuffix}`;
|
|
1062
|
+
} else {
|
|
1063
|
+
coverageText = `${attempted} attempted${opsSuffix}`;
|
|
1064
|
+
}
|
|
1049
1065
|
|
|
1050
1066
|
// --- Timeouts ---
|
|
1051
1067
|
const staticTimeouts = (stats.errorsByType && stats.errorsByType.static_timeout) || 0;
|
|
@@ -1108,9 +1124,7 @@ function buildDailyReportEmbed(stats, dailyAlerts, ledgerRollup) {
|
|
|
1108
1124
|
const healthText = `Up ${uptimeH}h${uptimeM}m | Heap ${heapMB}MB${jsonlInfo}`;
|
|
1109
1125
|
|
|
1110
1126
|
// --- Phase 0b: per-scan ledger rollup (operational coverage) ---
|
|
1111
|
-
//
|
|
1112
|
-
// numbers it displays); undefined → compute here; explicit null → omit the section.
|
|
1113
|
-
const ledger = ledgerRollup !== undefined ? ledgerRollup : safeLedgerRollup();
|
|
1127
|
+
// `ledger` was resolved above (Coverage uses it). explicit null → omit the section.
|
|
1114
1128
|
const ledgerField = formatLedgerField(ledger);
|
|
1115
1129
|
|
|
1116
1130
|
const now = new Date();
|
|
@@ -1207,6 +1221,12 @@ async function sendDailyReport(stats, dailyAlerts, recentlyScanned, downloadsCac
|
|
|
1207
1221
|
deferredProcessed: stats.deferredProcessed || 0,
|
|
1208
1222
|
deferredExpired: stats.deferredExpired || 0,
|
|
1209
1223
|
changesStreamPackages: stats.changesStreamPackages || 0,
|
|
1224
|
+
// Honest version-collapsed coverage (AUDIT 4): top-level mirror of the
|
|
1225
|
+
// ledger fields so trend analysis can read them without descending into
|
|
1226
|
+
// metrics.ledger. null when the ledger window was empty.
|
|
1227
|
+
distinctPackages: ledgerRollup ? (ledgerRollup.distinctPackages ?? null) : null,
|
|
1228
|
+
distinctScanned: ledgerRollup ? (ledgerRollup.distinctScanned ?? null) : null,
|
|
1229
|
+
distinctCoverage: ledgerRollup ? (ledgerRollup.distinctCoverage ?? null) : null,
|
|
1210
1230
|
restartsToday: stats.restartsToday || 0,
|
|
1211
1231
|
temporalLoadShed: stats.temporalLoadShed || 0,
|
|
1212
1232
|
queueHardDrops: stats.queueHardDrops || 0,
|