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:
- Bandwidth (
secv_scrape) — 10.5 years of continuous ISP usage data. Right-skewed, multiple regime shifts, an existing forecasting project to build on. - 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). - 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.pynow enumerates all non-system schemas inlist_tables, anddescribe_table/table_sampleacceptschema.table(or a bare name with cross-schema disambiguation).claude_readerwas 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.
| Property | Value |
|---|---|
| Time range | 2015-10-06 → 2026-05-06 (10.5 yr) |
| Rows | 21,514 |
| Granularity | ~daily until 2024, then ~hourly (avg interval 4.3 hr overall) |
| Columns | time_stamp, upstream, downstream, total (cumulative bytes); intervals add u_diff/d_diff/t_diff and rates |
| Strengths | Long history, multiple regime shifts (granularity change in 2024, COVID-era WFH, Minnie Nov 2024, kid arriving, ISP cap changes), right-skewed |
| Already used by | bandwidth-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.
| Property | Value |
|---|---|
| Time range | 2024-05-15 → 2025-10-26 (~17 months) |
| Rows | 689,946 |
| Distinct rides | 62 |
| Columns | time_stamp, _id (ride id), queue_time (smallint, minutes) |
| Joinable to | knoebels.ride_master, knoebels.LZ_attractions_io_poi for ride metadata (type, throughput, location) |
Why this is a curriculum gem:
- Right-skewed
queue_timedistribution (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.
| Property | Value |
|---|---|
| Time range | 2016-05-11 → 2026-05-06 (10 yr) |
mart.fact_plays rows | 67,044 |
| Users | 2 (67640fa18d9ec7f08167a0c1 = 49,282 plays since 2016; 676aafdcfef6f8fa0e3c161d = 17,762 plays since 2023-12-25) |
| Tracks | 11,771 distinct |
| Yearly volume | 499 (2016) → 6,811 (2020 — COVID jump) → 16,093 (2024 peak) → ~14,733 (2025) |
Key columns on fact_plays | played_at, owner_id, track_id, album_id, primary_artist_id, duration_ms, played_date_local, played_hour_local, played_dow_local |
| Joinable dims | dim_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.
| Property | Value |
|---|---|
| Time range | 2026-04-06 → 2026-05-07 (~31 days) |
| Rows | 5,973,183 |
| Granularity | per-query, sub-second timestamps |
| Key columns | request_ts, client_ip, client_name, duration_ms, response_type (CACHED / BLOCKED / CUSTOMDNS / RESOLVED / SPECIAL), question_type, question_name |
Distribution of response_type | CACHED 55%, BLOCKED 16%, CUSTOMDNS 16%, RESOLVED 6%, SPECIAL 6% |
| Strengths | Massive 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.
| Property | Value |
|---|---|
| Time range | 2026-04-07 → 2026-05-07 (~30 days) |
endpoint_results rows | 6,670 (recent retention only — older data lives in endpoint_uptimes aggregates) |
endpoint_uptimes rows | 6,258 hourly rollups, 2.69M total executions, 2.50M successes (overall ~93% success) |
| Key columns | success (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.
| Property | Value |
|---|---|
| Time range | 2025-12-09 → 2026-05-06 (~5 months) |
| Rows | 157,455 across 88 stat-tracked sensors |
| Sensor categories | Power (per-lamp wattage), water (whole-house meter, drinking water flow), HVAC humidity baseline, RV tanks (campsite_onecontrol_*), temperature, battery levels |
states table | 972,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)
| Table | Rows | Notes |
|---|---|---|
review_statistics | 1,938 | Per-subject correct/incorrect counts, percentage_correct |
daily_snapshot | 45 | SRS stage counts per day (apprentice/guru/master/etc.) |
level_progressions | 14 | Started/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
| Property | Value |
|---|---|
| Time range | 2022-02-22 → 2026-05-06 (~4 yr) |
transaction_journals rows | 1,064 |
| Joinable to | transactions, 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)
| Dataset | Reason |
|---|---|
smart_monitoring.smart_metrics | 18 rows total, single day. Backfill not in place. |
fitness_tracking.sessions | 7 sessions, all running. |
HA states (30-day window) | Too short for year-over-year work; use statistics instead. |
exploit_news | No tables. |
Module → Dataset Map
| Module | Primary | Secondary | Example question |
|---|---|---|---|
| 1. Hypothesis testing | Bandwidth | Blocky DNS, Gatus | Is weekend bandwidth different from weekday? Paired t-test on same-day-of-week pairs across 10 years. |
| 2. Confidence intervals | Bandwidth | HA water | Bootstrap CI on mean daily bandwidth; CI on the weekend-vs-weekday difference. |
| 3. Power & sample size | Bandwidth | Gatus | How many days do we need to detect a 5% bandwidth shift at 80% power? Golden-set sizing analog. |
| 4. Linear regression | Bandwidth | HA statistics, Firefly | Bandwidth ~ day-of-week + hour + month + cap-status. Diagnostics, multicollinearity, residuals. |
| 5. Logistic regression | Bandwidth cap (will-this-month-cap) | Gatus success, Wanikani correct | Predict P(monthly cap hit) from rolling rates and day-of-month. Calibration story. |
| 6. Non-parametric | Bandwidth | Blocky, Firefly | Mann-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-year | Blocky week-over-week | KS / 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)
| Question | Decision |
|---|---|
| Repo location | c0smere_devops/stats_curriculum/ (subdir) |
| Outdoor weather | Pull 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 reuse | Self-contained. Stats curriculum has its own DB queries / loaders; no import from bandwidth-prediction/. Keeps the curriculum portable. |
| Notebook tooling | marimo. Reactive Python notebooks, exports to standalone HTML and to WASM (interactive in-browser, no server) for embedding into the digital garden. |
| Data caching | Yes — 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 dataset | Cleared 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.