Skip to content

feat(netflow): singularity alert feed - #96

Merged
flamboh merged 14 commits into
codex/capture-coveragefrom
t3code/singularity-feed
Aug 22, 2026
Merged

feat(netflow): singularity alert feed#96
flamboh merged 14 commits into
codex/capture-coveragefrom
t3code/singularity-feed

Conversation

@flamboh

@flamboh flamboh commented Aug 21, 2026

Copy link
Copy Markdown
Owner

Singularity (MAAD) scores how anomalous each IP address is within a trace's address population, but ATLANTIS had no way to watch a live capture tree and surface those anomalies continuously.

This adds a rolling alert feed: a new long-running netflow-db feed <dataset> subcommand polls a dataset's nfcapd tree, and for each completed five-minute window unions the distinct IPv4 addresses across members, scores them with a Rust port of Singularities.hs, and records addresses beyond calibrated alpha thresholds into alerts.sqlite beside the dataset's product database (rolling ~7-day retention). The dashboard reads that file per dataset on a new /alerts page.

What's in here

  • singularity.rs: Rust port of MAAD's per-address alpha scoring, plus a netflow-db singularity CLI for stdin/file scoring. Conformance-verified against the Haskell reference on 24 real uOregon windows (7.6M address comparisons, zero violations; max alpha deviation 7.7e-15).
  • feed.rs: the feed loop — registry-driven config, bounded window discovery with a grace rule for incomplete windows, per-window transactional writes, retention pruning, --backfill, --once.
  • Default thresholds high = 2.0, low = 0.3, calibrated on 200 windows spanning 13 months (methodology + sensitivity in docs/agent/singularity-calibration.md). A typical window records ~20 alerts (p10–p90: 14–25). Both tails alert: high alpha = isolated/sparse address-space region, low alpha = deep inside a dense cluster.
  • Web: /api/alerts + a dataset-scoped /datasets/<id>/alerts page (Dashboard | Alerts tabs) — an address-centric feed: one row per anomalous address over a selectable horizon (1h/6h/24h/7d), showing its peak alpha in that horizon, last-seen, times-flagged persistence, and a "new" badge for fresh entrants; sorted by severity (distance past threshold) with a recency toggle, tail filter, and 30 s auto-refresh while visible. Windows are aggregation evidence, not page structure. The alerts DB is opened read-only; presence of alerts.sqlite is the feature flag. D1 deployments report feed.present = false — this is local-driver-only for now.

Decisions worth reviewing

  • The alert DB is an ephemeral rolling buffer owned by the feed, deliberately not a pipeline product database — no dataset identity or coverage semantics, safe to delete anytime.
  • Feed depends on the dataset's registry config only, not on a pipeline run having produced netflow.sqlite.
  • Backfill deeper than retention is clamped (processing windows that would be pruned in the same pass is wasted work).
  • A window whose files all fail to read is skipped and retried next pass, never marked processed; a regression test covers the previous stall-on-gap behavior.

How to exercise

  1. Build the pinned nfdump fork (./vendor/scripts/compile-nfdump.sh), then run
    netflow-db feed <dataset-id> --nfdump target/nfdump/libexec/nfdump --backfill 2h --once
    against a dataset from datasets.json. Expect one windows row per completed five-minute window in data/<dataset>/alerts.sqlite, ~14–25 alerts each on uOregon-like traffic.
  2. Start the web app (ATLANTIS_DB_DRIVER=sqlite bun run dev:web), open /datasets/<id>/alerts: feed sections newest-first, tail badges with tooltips, "Feed idle"/"Live" status per window age; datasets without a feed show the start-command card.
  3. Cross-check scoring: netflow-db singularity <file-of-ipv4s> against vendor/maad Singularities -1 <file>.

Verification

  • bun run format / lint / typecheck clean; bun run test:db (131 lib tests + integration, incl. 8 feed + 7 singularity) and bun run test:web (87 tests, 15 new) pass.
  • Conformance + calibration report: docs/agent/singularity-calibration.md.
  • Manual end-to-end run over six real uOregon windows (both members, ~345k addresses per window, 5–19 s per window) verified alert rows, retention pruning, and the dashboard rendering them.

Built by Claude (Fable 5) orchestrating gpt-5.6-sol (xhigh) implementation subagents via Claude Code.

@flamboh
flamboh force-pushed the t3code/singularity-feed branch 2 times, most recently from d0f8d7e to 16e6141 Compare August 22, 2026 09:54
@flamboh
flamboh merged commit c185c20 into main Aug 22, 2026
3 checks passed
@flamboh
flamboh deleted the t3code/singularity-feed branch August 22, 2026 10:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant