inventory

Phase 1 Inventory — Stats Curriculum

What’s in the homelab DBs, what’s actually usable, and which datasets map to which curriculum modules. Generated 2026-05-06 from claude_reader access on stygies (MariaDB) + phlegethon (PostgreSQL).

TL;DR

Three strong spine datasets:

  1. Bandwidth (secv_scrape) — 10.5 years of continuous ISP usage data. Right-skewed, multiple regime shifts, an existing forecasting project to build on.
  2. Spotify (your_spotify) — 10 years of listening history, 67K plays, 2 users (paired comparison from late-2023 onward), rich track/artist/genre dimensions. Direct AI-eval analogue (recommendation systems, taste drift).
  3. Knoebels queue times (gp0.knoebels) — 690K rows, 62 rides, May 2024 → Oct 2025 of amusement-park ride wait times. Right-skewed, paired-ride comparisons, day/season seasonality, year-over-year drift. Likely the most blog-friendly dataset in the homelab.

Supporting datasets fill in:

  • Blocky DNS logs — 5.9M rows / 1 month — count/rate analysis, multi-class outcomes, drift between weeks
  • Gatus endpoint results — binary success outcomes across 64 endpoints — natural fit for logistic regression and proportions
  • HA states + statistics — 509 sensors, ~5 months of long-term hourly data — physical paired comparisons (HVAC, water, power)
  • Wanikani review stats — Bernoulli outcomes (correct/incorrect) by item — small but clean
  • Firefly transactions — 4 years of categorical+continuous financial data — robust regression candidate

Datasets with too little data for stats work: SMART monitoring (18 rows), fitness sessions (7 runs), KOA scraper (19 rows), wifi_scans (1 week), HA states (30-day recorder retention).

MCP fix applied 2026-05-06: sql-mcp/server.py now enumerates all non-system schemas in list_tables, and describe_table / table_sample accept schema.table (or a bare name with cross-schema disambiguation). claude_reader was granted on every previously-missed schema. Discovery was re-run after the fix — the three datasets above were among the missed schemas.


Tier 1 — Spine datasets

secv_scrape.scrape_data and scrape_data_intervals (stygies)

ISP usage scraper. The headline dataset.

PropertyValue
Time range2015-10-06 → 2026-05-06 (10.5 yr)
Rows21,514
Granularity~daily until 2024, then ~hourly (avg interval 4.3 hr overall)
Columnstime_stamp, upstream, downstream, total (cumulative bytes); intervals add u_diff/d_diff/t_diff and rates
StrengthsLong history, multiple regime shifts (granularity change in 2024, COVID-era WFH, Minnie Nov 2024, kid arriving, ISP cap changes), right-skewed
Already used bybandwidth-prediction/ project (target leakage, lagged features, time-series CV)

Companion tables: bandwidth_cap_history, bandwidth_forecast, monthly_totals, rolling_24hr_summary. The cap history is gold for logistic regression (was-this-month-capped is a Bernoulli outcome with real consequences).

Maps to Modules 1, 2, 3, 4, 6, 7 (drift detection capstone uses this).

gp0.knoebels.LZ_attractions_io_queuetimes (phlegethon)

Amusement park ride queue times (Knoebels, PA), scraped from a public attractions API.

PropertyValue
Time range2024-05-15 → 2025-10-26 (~17 months)
Rows689,946
Distinct rides62
Columnstime_stamp, _id (ride id), queue_time (smallint, minutes)
Joinable toknoebels.ride_master, knoebels.LZ_attractions_io_poi for ride metadata (type, throughput, location)

Why this is a curriculum gem:

  • Right-skewed queue_time distribution (most rides have short waits; a few rides dominate)
  • Strong daily/weekly/seasonal seasonality (weekends, summer peak, weather effects if joinable)
  • Per-ride paired comparisons (62 rides → many natural pairs to test)
  • Year-over-year drift on the same ride is testable (May–Oct 2024 vs May–Oct 2025)
  • Clear AI-eval narrative: “predict queue time” is a regression problem with calibration consequences

Maps to Modules 1, 2, 4, 6, 7. Strong blog headliner candidate alongside bandwidth and Spotify.

your_spotify.mart.fact_plays + dims (phlegethon)

10 years of Spotify listening history, recently migrated from MongoDB to Postgres via a staging → mart pipeline. Probably the most blog-friendly dataset in the homelab.

PropertyValue
Time range2016-05-11 → 2026-05-06 (10 yr)
mart.fact_plays rows67,044
Users2 (67640fa18d9ec7f08167a0c1 = 49,282 plays since 2016; 676aafdcfef6f8fa0e3c161d = 17,762 plays since 2023-12-25)
Tracks11,771 distinct
Yearly volume499 (2016) → 6,811 (2020 — COVID jump) → 16,093 (2024 peak) → ~14,733 (2025)
Key columns on fact_playsplayed_at, owner_id, track_id, album_id, primary_artist_id, duration_ms, played_date_local, played_hour_local, played_dow_local
Joinable dimsdim_track (popularity, explicit, duration), dim_artist (popularity, followers), bridge_artist_genre (genre tags), dim_album, dim_user

Natural change points: 2nd user joining late 2023 (paired comparison from there onward), the 2020 COVID jump in plays, year-over-year taste drift.

Maps to all 7 modules. Particularly strong for:

  • Module 1 — paired t-test on weekly play counts between you and Lindsey post-2023
  • Module 4 — regression of daily plays on day-of-week + season + user
  • Module 5 — predict P(skip) from track features (if skip data exists in raw — needs verification) or P(explicit-track-played) from owner + hour
  • Module 6 — Mann-Whitney comparing genre-listening durations across users
  • Module 7 — drift in genre/artist distribution year-over-year (publishable: “ten years of my Spotify, did my taste actually change?”)

blocky.log_entries (phlegethon)

DNS query log from the Blocky resolver in LXC 104.

PropertyValue
Time range2026-04-06 → 2026-05-07 (~31 days)
Rows5,973,183
Granularityper-query, sub-second timestamps
Key columnsrequest_ts, client_ip, client_name, duration_ms, response_type (CACHED / BLOCKED / CUSTOMDNS / RESOLVED / SPECIAL), question_type, question_name
Distribution of response_typeCACHED 55%, BLOCKED 16%, CUSTOMDNS 16%, RESOLVED 6%, SPECIAL 6%
StrengthsMassive count data, multi-client (per-device), categorical outcomes, time-of-day rhythm

Maps to Modules 1, 2, 6, 7 — count rate comparisons across clients/days; drift in client behavior week-over-week; permutation tests on client exchangeability.

gatus_db.endpoint_results and endpoint_uptimes (phlegethon)

Uptime monitor results across 64 internal/external endpoints.

PropertyValue
Time range2026-04-07 → 2026-05-07 (~30 days)
endpoint_results rows6,670 (recent retention only — older data lives in endpoint_uptimes aggregates)
endpoint_uptimes rows6,258 hourly rollups, 2.69M total executions, 2.50M successes (overall ~93% success)
Key columnssuccess (bool), duration (ms), status (HTTP code), timestamp, endpoint_id

Maps to Module 5 (logistic regression on success vs hour/endpoint), Module 6 (non-parametric comparison of duration distributions), Module 7 (drift in latency).

homeassistant.statistics + statistics_meta (stygies)

Long-term hourly sensor aggregates. Note: short-term states table is recorder-retention-bound at 30 days, so we work mostly from statistics.

PropertyValue
Time range2025-12-09 → 2026-05-06 (~5 months)
Rows157,455 across 88 stat-tracked sensors
Sensor categoriesPower (per-lamp wattage), water (whole-house meter, drinking water flow), HVAC humidity baseline, RV tanks (campsite_onecontrol_*), temperature, battery levels
states table972,743 rows, 509 entities, 30-day window

Caveat on the Minnie example from the handoff: Minnie was born Nov 2025 and joined the household Jan 2026 — that is within the statistics window (~3 weeks of pre, ~4 months of post). The harder issue is that her presence likely doesn’t move most sensor signal: Wes’s expectation is that water usage is the only realistic candidate, and even that’s not guaranteed to show. Better within-window comparisons: heating-season vs shoulder-season power, weekday vs weekend, before/after a specific automation change with a known date.

Maps to Modules 1, 4 (regress room temp on outdoor temp + HVAC state — needs an outdoor source).


Tier 2 — Supporting datasets

wanikani (stygies)

TableRowsNotes
review_statistics1,938Per-subject correct/incorrect counts, percentage_correct
daily_snapshot45SRS stage counts per day (apprentice/guru/master/etc.)
level_progressions14Started/passed timestamps for 14 levels (2017–2024)

Excellent Bernoulli/binomial structure (correct vs incorrect on review attempts). Small, but clean.

Maps to Module 5 (logistic regression: predict review correctness from item features) and Module 1 (proportion tests across SRS stages).

firefly (stygies) — financial transactions

PropertyValue
Time range2022-02-22 → 2026-05-06 (~4 yr)
transaction_journals rows1,064
Joinable totransactions, categories, budgets, tags for amount + classification

Maps to Module 4 (regression of monthly spend on category × time), Module 6 (non-parametric — finance is rarely normal). Privacy consideration: blog drafts on this would need to anonymize categories or use ratios, not absolute amounts.

koa_scraper.weekend_scrapes and crowding_estimates (stygies)

Currently only 19 rows — too small. Worth re-checking before Module 7 if scraping has been re-enabled.

campsite.wifi_scans (stygies)

133 BSSIDs over 1 week, 18 open networks. Good shape (categorical security level, signal strength, frequency band) but volume is low. Could feed a side example in Module 1 (proportion of open networks vs secured) but not a primary case.


Tier 3 — Skip (insufficient data)

DatasetReason
smart_monitoring.smart_metrics18 rows total, single day. Backfill not in place.
fitness_tracking.sessions7 sessions, all running.
HA states (30-day window)Too short for year-over-year work; use statistics instead.
exploit_newsNo tables.

Module → Dataset Map

ModulePrimarySecondaryExample question
1. Hypothesis testingBandwidthBlocky DNS, GatusIs weekend bandwidth different from weekday? Paired t-test on same-day-of-week pairs across 10 years.
2. Confidence intervalsBandwidthHA waterBootstrap CI on mean daily bandwidth; CI on the weekend-vs-weekday difference.
3. Power & sample sizeBandwidthGatusHow many days do we need to detect a 5% bandwidth shift at 80% power? Golden-set sizing analog.
4. Linear regressionBandwidthHA statistics, FireflyBandwidth ~ day-of-week + hour + month + cap-status. Diagnostics, multicollinearity, residuals.
5. Logistic regressionBandwidth cap (will-this-month-cap)Gatus success, Wanikani correctPredict P(monthly cap hit) from rolling rates and day-of-month. Calibration story.
6. Non-parametricBandwidthBlocky, FireflyMann-Whitney comparing bandwidth distributions across years; permutation test on client DNS rates.
7. Drift detection (capstone)Bandwidth 2017 → 2026 OR Knoebels season-over-season OR Spotify genre year-over-yearBlocky week-over-weekKS / Wasserstein / PSI on daily-total bandwidth distributions, or on per-ride queue-time distributions across the two operating seasons, or on genre-share distributions. All three are publishable. The Knoebels angle is the most accessible to a non-technical audience.

Decisions (locked 2026-05-06)

QuestionDecision
Repo locationc0smere_devops/stats_curriculum/ (subdir)
Outdoor weatherPull from a weather API (NWS or OpenWeatherMap); indoor temps from existing Zigbee/heater sensors.
HA change-points (Module 1, etc.)None on the calendar with a known date. Use heating-season vs shoulder-season power consumption as the within-window comparison instead of the Minnie example.
Bandwidth-prediction reuseSelf-contained. Stats curriculum has its own DB queries / loaders; no import from bandwidth-prediction/. Keeps the curriculum portable.
Notebook toolingmarimo. Reactive Python notebooks, exports to standalone HTML and to WASM (interactive in-browser, no server) for embedding into the digital garden.
Data cachingYes — shared data/ directory with parquet snapshots, refreshable via a make refresh target. Notebooks read from the cache so they’re offline-friendly and consistent across runs.
Knoebels datasetCleared for use, named in writeups. Public attractions.io endpoint used by their mobile apps — no obfuscation needed.

Prerequisites before Phase 2

  • Knoebels scraper: Resolved 2026-05-06. Containerized + redeployed to cyrion under /home/nox/docker/kuh-no-bowls/ with a systemd timer (*-*-* 09..23:00/5:00). Missed the first two weekends of 2026 but Memorial Day weekend onward will be captured.

Wesley Ray · blog · git · resume