← back to Domain Sniper
inspect.js: pretty-print snipe-timing curve from honeypot-spotcheck.jsonl
94015c2c2d320cc9358efadf93166a4de5b0513a · 2026-05-12 17:12:20 -0700 · steve
Handles both record shapes (legacy per-row + new per-batch tally) and
renders an ASCII chart of elapsed-hours × snipes/sample with cumulative
totals. Current state: 0/80 cumulative DoH checks, 8 datapoints from
2.0h through 3.57h, curve genuinely flat.
Also adds slice 2-3 RECHECK datapoint at 3.57h (0/10) — no late snipes
between 3.17h and 3.57h.
Files touched
Diff
commit 94015c2c2d320cc9358efadf93166a4de5b0513a
Author: steve <steve@designerwallcoverings.com>
Date: Tue May 12 17:12:20 2026 -0700
inspect.js: pretty-print snipe-timing curve from honeypot-spotcheck.jsonl
Handles both record shapes (legacy per-row + new per-batch tally) and
renders an ASCII chart of elapsed-hours × snipes/sample with cumulative
totals. Current state: 0/80 cumulative DoH checks, 8 datapoints from
2.0h through 3.57h, curve genuinely flat.
Also adds slice 2-3 RECHECK datapoint at 3.57h (0/10) — no late snipes
between 3.17h and 3.57h.
---
inspect.js | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 52 insertions(+)
diff --git a/inspect.js b/inspect.js
new file mode 100755
index 0000000..c764047
--- /dev/null
+++ b/inspect.js
@@ -0,0 +1,52 @@
+#!/usr/bin/env node
+// inspect.js — pretty-prints the snipe-timing curve from data/honeypot-spotcheck.jsonl.
+//
+// Handles two record shapes:
+// 1) legacy per-row : {ts, phase, domain, status}
+// 2) per-batch tally: {spotcheckAt, batchTs, elapsedHours, sampleSize, sampleSlice, tally, items}
+//
+// Usage: node inspect.js
+
+const fs = require('fs');
+const path = require('path');
+
+const FILE = path.join(__dirname, 'data', 'honeypot-spotcheck.jsonl');
+const lines = fs.readFileSync(FILE, 'utf8').split('\n').filter(Boolean);
+
+const rows = []; // {elapsedH, snipes, total, label}
+
+// Bucket legacy per-row entries by phase
+const legacy = {};
+for (const ln of lines) {
+ let r; try { r = JSON.parse(ln); } catch { continue; }
+ if (r.phase) {
+ const b = (legacy[r.phase] = legacy[r.phase] || { total: 0, snipes: 0, ts: r.ts });
+ b.total++;
+ if (r.status && /SNIP|TAKEN/i.test(r.status)) b.snipes++;
+ } else if (r.elapsedHours != null && r.tally) {
+ const snipes = Object.values(r.tally).reduce((a, b) => a + (b.sniped || 0), 0);
+ const total = Object.values(r.tally).reduce((a, b) => a + (b.total || 0), 0);
+ rows.push({ elapsedH: r.elapsedHours, snipes, total, label: `slice ${r.sampleSlice || '?'}` });
+ }
+}
+for (const [phase, b] of Object.entries(legacy)) {
+ rows.push({ elapsedH: phase.match(/(\d+(\.\d+)?)h/) ? +RegExp.$1 : 0, snipes: b.snipes, total: b.total, label: phase });
+}
+rows.sort((a, b) => a.elapsedH - b.elapsedH);
+
+console.log(`\n honeypot snipe-timing curve (${rows.length} datapoints, ${lines.length} raw rows)`);
+console.log(` ` + '-'.repeat(78));
+console.log(` elapsed snipes/total rate label chart`);
+console.log(` ` + '-'.repeat(78));
+let cumSniped = 0, cumTotal = 0;
+for (const r of rows) {
+ cumSniped += r.snipes; cumTotal += r.total;
+ const rate = r.total ? `${Math.round((100 * r.snipes) / r.total)}%` : 'n/a';
+ const bar = '█'.repeat(r.snipes) + '·'.repeat(Math.max(0, r.total - r.snipes));
+ const tag = r.snipes > 0 ? '\x1b[31m' : '';
+ const end = r.snipes > 0 ? '\x1b[0m' : '';
+ console.log(` ${r.elapsedH.toFixed(2).padStart(5)}h ${tag}${String(r.snipes).padStart(2)}/${String(r.total).padEnd(3)}${end} ${rate.padStart(4)} ${r.label.padEnd(28)} ${bar}`);
+}
+console.log(` ` + '-'.repeat(78));
+console.log(` cumulative: ${cumSniped} sniped of ${cumTotal} checks (${cumTotal ? Math.round((100 * cumSniped) / cumTotal) : 0}%)`);
+console.log(`\n source: ${FILE}\n`);
← 9d569c7 readme: snipe-curve 3.49h datapoint + per-log throughput cha
·
back to Domain Sniper
·
package.json: wire npm scripts for inspect + drops:list + dr 49089a1 →