Change Log
Running record of meaningful changes across all projects. Updated by Claude Code after every session where code was changed or something was deployed.
2026-04-16
EcoCell — Supplier Price Sheet (ALL 3 PHASES SHIPPED)
Live: https://myecocell.com/pricesheet (public, no login) · /pricesheet-admin (owner)
Phase 1 — Scraper + compute + cron:
- New tables —
pricesheet_source, pricesheet, pricesheet_overrides, pricesheet_changes, pricesheet_scans, pricesheet_deductions. Created via raw SQL migrations (not drizzle-kit push — schema files are drifted vs live DB and a push would drop 15+ live columns). (scripts/migrate-pricesheet.js, scripts/migrate-pricesheet-deductions.js, server/db/schema/pricesheet.js)
- Atlas scraper — Downloads both Atlas Mobile public sheets (Used + NIB) as xlsx, parses 11 categories (iphone_used/nib, samsung, pixel, ipad_used/nib, watch, macbook, mdm, parts, accessories_nib). 3,398 rows per run. (
server/services/atlas-scraper.js)
- Deductions scraper — Third-party per-iPhone × per-issue deduction grid. 38 models × 15 issues. (
server/services/deductions-scraper.js)
- Compute pipeline — Diff-based sync with batched upserts; 3,400-row sync runs in ~4s. Idempotent. (
server/services/pricesheet-compute.js)
- Cron — 8am / 1pm / 6pm ET for Atlas, 8am only for deductions. (
server/services/pricesheet-cron.js)
Phase 2 — Owner dashboard (/pricesheet-admin, manager+ role):
- Category tabs; per-cell override modal (Atlas minus $X, or clear to match)
- Bulk adjust by category
- Recent changes panel (Atlas + override edits)
- Run-now button + last-scan timestamp
- (
client/src/pages/PriceSheet.jsx, server/routes/pricesheet.js)
Phase 3 — Public page (myecocell.com/pricesheet, no auth):
- EcoCell-branded, contact block (Ernie / Atlanta / WhatsApp / email)
- All 11 categories as tabs, grouped by model/storage/carrier
- Our price only, '—' for not-buying
- Grading guide footer
- 60s in-memory cache on the public API
- Bypasses auth via early route check in App.jsx
- (
client/src/pages/PriceSheetPublic.jsx, server/routes/pricesheet-public.js)
Deductions are scraped but NOT shown publicly yet — boss to decide later how to surface them.
2026-04-10
EdgeClaw — Summary Bar Fixes & F5 Tie Tracking
- Fixed Our Model summary stats — Edge was 100x inflated (missing /100), win% was piggybacking on Pinnacle's outcome. Now both models independently check their best side vs Result column. (
src/pipeline/data-status/data-view.ts)
- Added
model_best_side column — Pinnacle and edge model each get their own best side. Display renamed to "Pin Best Side" / "Model Best Side". (src/pipeline/sports/edge-scanner.ts, src/pipeline/data-status/table-config.ts)
- Added Result column to spreads/ML views — Spreads: did team cover? ML: did team win? Uses live scores for full-game, Kalshi settlement for F5. (
src/pipeline/data-status/data-view.ts)
- F5 tie contract tracking — Edge scanner now records TIE contracts using Poisson tie probability. New
is_tie column flags tied games. Settlement detects ties from Kalshi API. (src/pipeline/sports/edge-scanner.ts, src/pipeline/sports/scanner-bridge.ts)
2026-04-09
EdgeClaw — Closer Org Chart Scraper
- Built real closer/setup role identification — Scrapes ESPN closer org chart daily (CloserMonkey backup). Was: guessing closer = highest-usage reliever (wrong — middle innings guys throw more). Now uses actual named closers. Handles co-closers and committee teams. (
src/pipeline/data/scrapers/scrape-mlb-bullpen.ts, src/cron/scheduler.ts)
EdgeClaw — Kalshi Rate Limiting + DB Schema Fixes
- Added exponential backoff on Kalshi 429s —
kalshiFetch() now retries up to 3x with 2s/4s/8s delays on rate limits. Was: throw immediately. (src/pipeline/markets/kalshi.ts)
- Added backoff to weather market tracker —
fetchWeatherMarkets() now retries on 429 + 1s delay between series. Was: no delay, all 19+ series fired simultaneously. (src/pipeline/weather/market-tracker.ts)
- Increased inter-page delay — Kalshi pagination delay 500ms→1500ms. (
kalshi.ts)
- Increased inter-series delay — Sports collector non-prop series 100ms→500ms, prop series 1000ms→1500ms. (
src/pipeline/sports/collector.ts)
- Staggered culture Kalshi schedule — Moved from :10/:40 to :20/:50 to avoid overlapping sports/politics. (
src/cron/scheduler.ts)
- Fixed crosswalk wrong DB —
mlb_prop_lines queried from mlb-batting.db (doesn't exist there) → now uses getMlbPropLinesDb(). (src/pipeline/data/scrapers/mlb-player-crosswalk.ts)
- Fixed matchup context bad column —
stat_type doesn't exist in mlb_sp_baselines. Changed to literal 'era' alias. (src/pipeline/data/scrapers/mlb-prop-matchup-context.ts)
- Fixed tier2 metrics wrong DB —
computeSPQC() queried mlb_sp_baselines via mlb-model.db (table not there) → now uses getMlbPitchingDb(). (src/pipeline/data/scrapers/mlb-tier2-metrics.ts)
- Result: 429 errors dropped from 52K/8h to ~1 since restart. All 3 broken cron jobs should now succeed.
EdgeClaw — DraftKings Removal (Boss Decision)
- Removed DraftKings from entire pipeline — Boss decided FD + Pinnacle are the only anchors needed. SBR multi-book used for alternative lines reference. 18 files changed, 612 lines deleted.
- Deleted:
src/pipeline/data/draftkings.ts (entire scraper), getDkMlbPropsDb() from mlb-db.ts, dk-mlb-props.db → .deprecated
- Cleaned: All 4 edge scanners (DK cross-validation → null), odds-collector (Pinnacle-only), scrape-player-props (FD-only BOOKMAKERS), crosswalk (stop populating DK names), steam detector (removed dual-book detection), props-collector, dashboard views, desk configs, source tables, docs
- Kept: DK in SBR scraper (SBR collects all 6 books), DB CHECK constraints (historical data), DK column in crosswalk table (SQLite can't drop)
2026-04-08
EdgeClaw — MLB Prop Curves Fixes + Settlement System
- Fixed threshold bug — Curves had threshold=0 for all strikeout rows. Three bugs: reading
line instead of threshold, dedupe by market only (losing alt lines), PROP_CONFIGS had wrong market names. (src/pipeline/data/scrapers/mlb-prop-probability-curves.ts)
- Filtered combined pitcher props — Skip "Player A & Player B" rows from FD. (
mlb-prop-probability-curves.ts)
- Built MLB prop settlement — New file settles both curves (beat-books) and edges (beat-Kalshi) using MLB Stats API box scores. Cron every 2h 3PM-1AM ET. (
src/pipeline/data/scrapers/settle-mlb-props.ts, src/cron/scheduler.ts)
- Added is_main_line flag — Identifies FD's headline line per player (closest to 50/50). (
mlb-prop-probability-curves.ts)
- Added settlement columns to curves — actual_stat, outcome, fd_was_right, model_was_right, fd_error, model_error, settled_at. (
mlb-prop-probability-curves.ts)
- Fixed dashboard 125% bug — edge_yes/edge_no stored as 0-100 but dashboard multiplied by 100 again. Removed from ×100 formatter. (
src/pipeline/data-status/data-view.ts)
- Added name normalization — Strips accents and Jr/Sr suffixes for cross-source matching. Missing model data: 42→14 players. (
mlb-prop-probability-curves.ts, settle-mlb-props.ts)
- Added changelogs to desk templates — Both game and player props templates now have running changelogs with Changes + Boss Notes sections. (
docs/desk-template-game.md, docs/desk-template-player-props.md)
EcoCell — Post-Migration Bug Fixes
- Fixed 8 PostgreSQL migration bugs — Optimistic lock, async sequence numbers, transaction wrappers, Postgres error codes, date direction, IMEI regex, notification cleanup, removed better-sqlite3. (Multiple files in
server/routes/ and server/db/)
2026-04-06 (continued)
EdgeClaw — MLB Prop Edge Scanner + Analyst Pipeline + Dashboard Organization
- Fixed MLB prop edge scanner routing — 8/10/2/6 cron was calling generic scanner (empty table). Pointed to dedicated MLB scanner. Fixed both regular and closing scans. (File:
src/cron/scheduler.ts)
- Built NegBin model anchor for pitcher strikeouts — Per council ruling: per-PA rates, Bayesian shrinkage (k=60), player-specific NegBin dispersion from game logs. (File:
src/pipeline/data/scrapers/mlb-prop-edge-scanner.ts)
- Built synthetic DK anchor for HRR — Derives H+R+RBI lambda from DraftKings individual hit/run/RBI lines. (File:
src/pipeline/data/scrapers/mlb-prop-edge-scanner.ts)
- Built synthetic book anchor for home runs — Median Over price from BetOnline/BetRivers/WilliamHill with vig removal, ZIP distribution. (File:
src/pipeline/data/scrapers/mlb-prop-edge-scanner.ts)
- Fixed name matching — Added
matchPlayerToMap() helper: strips Jr./Sr. suffixes, fuzzy match for Kalshi misspellings (e.g., SUREZ→Suarez). All scanners use it. (File: src/pipeline/data/scrapers/mlb-prop-edge-scanner.ts)
- Built model backfill for orphan book rows — Computes NegBin model values on the fly for K book rows that have no model match (games already started). 542 rows backfilled. (File:
src/pipeline/data/scrapers/mlb-prop-edge-scanner.ts)
- Fixed blank fields on model rows — home_team, away_team, event_id now populated from schedule. Date filter added to only price today's games. (File:
src/pipeline/data/scrapers/mlb-prop-edge-scanner.ts)
- Analyst Pipeline Council Ruling — Full 5-model council (unanimous Option C): independent parallel analysts + mechanical combination + monthly calibration council. Models: Opus 4.6 Max Reasoning (native), Gemini 3.1 Pro (API), gpt-oss-120b (API). Spec saved. (File:
docs/analyst-pipeline-spec.md)
- Dashboard document groups — Organized 21 docs into 4 groups: System Design, Ops, Project Tracking, Reference. Group landing pages with clean links. (Files:
src/pipeline/data-status/trackers.ts, src/pipeline/data-status/dashboard.ts, src/pipeline/data-status/routes.ts, src/pipeline/data-status/types.ts)
- 6 organizational systems deployed — Pre-session commit, change log, branch workflow, pre-flight checklist, session summaries, health monitor. Rules in both CLAUDE.md files. (Files:
CLAUDE.md, ~/ecocell/CLAUDE.md, scripts/post-restart-check.sh, scripts/health-monitor.sh)
- Created /switch and /resume commands — Session state save + project switching with clean context. (Files:
~/.claude/commands/switch.md, ~/.claude/commands/resume.md)
- Removed tmux auto-attach from .bashrc — New SSH tabs get fresh shell. (File:
~/.bashrc)
2026-04-06 (7:15 PM - 9:15 AM ET)
EdgeClaw — MLB Data Isolation + Freshness Tracker
- Fixed stale MLB weather scraper — Added
scrapeAllGameWeather() export, added to recovery queue. Was missing from recovery list so never ran after crash. (Files: src/pipeline/data/scrapers/scrape-mlb-weather.ts, src/cron/scheduler.ts)
- Recovery queue cleanup — Removed 28 scrapers for ToDo-group desks (NHL, NBA, NCAAB, Soccer) from recovery queue. MLB weather no longer blocked behind 20+ dead scrapers. (File:
src/cron/scheduler.ts)
- Blocked live data collection —
triggerKalshiOnPinnacleMove now skips games that already started. Closing snapshots fire 1 min before game start instead of at game start. (File: src/pipeline/sports/collector.ts)
- Removed Sagarin from MLB desk — Only covers NHL/NBA, not MLB. (File:
src/pipeline/data-status/desk-config.ts)
- Architecture map — Visual HTML diagram of full system at
/data-status/architecture. (File: src/pipeline/data-status/architecture-map.html, src/pipeline/data-status/routes.ts)
- Created
kalshi-mlb-prices.db — Isolated database for Kalshi game lines. Scan windows (6am/8am/10am/2pm/6pm/close), same-day only, no settled prices. Columns: scan_type, game_date, game_time, exec_price, spread. Human-readable ticker formatting. Edge scanner reads from here. (Files: src/pipeline/sports/mlb-dual-write.ts, src/pipeline/sports/scanner-bridge.ts, src/pipeline/data-status/source-tables.ts)
- Created
pinnacle-mlb.db — Isolated database for Pinnacle sharp odds (full game + F5 + team totals). Dedicated fixed-schedule cron at :02 past hour. Doubleheader support with game_number. Edge scanner reads from here. (Files: src/pipeline/sports/mlb-dual-write.ts, src/pipeline/sports/edge-scanner.ts, src/cron/scheduler.ts)
- Removed double Pinnacle scrape — MLB removed from collector's adaptive loop since dedicated cron handles it. (File:
src/pipeline/sports/collector.ts)
- Added 6AM scan window — Kalshi and Pinnacle now collect at 6AM/8AM/10AM/2PM/6PM ET. (File:
src/cron/scheduler.ts)
- Edge scanner offset to :10 — Runs 10 minutes after data collection so prices are fresh. Added 6AM scan. (File:
src/cron/scheduler.ts)
- Fixed model anchor bug — Totals no longer get negative signs (was spread-only sign convention bleeding into totals). (File:
src/pipeline/sports/edge-scanner.ts)
- Purged test/settled/live data — Removed 432K event_triggered, 721K settled prices from kalshi_mlb_prices. Removed 482K off-window rows. Removed 37K non-game-day rows. Removed 722K settled props. Purged test scan types from edge scanner. (Database cleanup)
- Column filters on MLB views — Same Google Sheets-style filtering as edge scanner tables. (File:
src/pipeline/data-status/data-view.ts)
- DraftKings team totals scraper — Written but unused. Pinnacle doesn't offer MLB team totals; edge scanner implies them from total+spread. (File:
src/pipeline/data/draftkings.ts)
- Quality gate fixes — require()→ESM import (crash fix), SQL GROUP BY HAVING→proper JOIN (data correctness), cross-connection transaction fix, decimalToAmerican >1 guard (div by zero), midnight display fix. (Multiple files)
- Freshness tracking for Pinnacle MLB — Dashboard now shows fresh status after each Pinnacle cron run. (File:
src/cron/scheduler.ts)
- Refreshed stale MLB stats — Manually ran xFIP, quality composite, bullpen usage index, derived metrics after missed 11AM batch.
- Freshness Tracker (council ruling) — Full 5-model council (Opus/Sonnet/Gemini/Grok/gpt-oss) ruled: passive poller, central SQLite, hardcoded config, per-table tracking. Built and deployed: 5-min cron, 24 MLB sources, Telegram alerts, dead-man switch. (File:
src/pipeline/freshness-poller.ts)
- Desk Isolation Checklist — 13-item checklist for isolating each desk. MLB audit started, 0/13 checked off. (File:
docs/desk-isolation-checklist.md)
2026-04-05
EdgeClaw
- Fixed MLB prop edge scanner — The 8/10/2/6 cron was calling the wrong scanner (
scanPropEdges('mlb') from the generic scanner which reads from empty player_props table). Pointed it to scanMlbPropEdges() from the dedicated MLB scanner that reads from mlb_prop_lines. Fixed in both regular and closing scan schedules. All edge detection sources now fresh. (File: src/cron/scheduler.ts)
- Added VPS Quick Reference doc — SSH, Claude sessions, tmux, port forwarding, slash commands. (File:
docs/vps-quick-reference.md)
- Added Git Crash Course doc — Full vibe coding crash course with Git commands and reference card. (File:
docs/git-crash-course.md)
- Added /switch and /resume slash commands — Save session state and switch between EdgeClaw and EcoCell with clean context. (Files:
~/.claude/commands/switch.md, ~/.claude/commands/resume.md)
- Added Pre-Session Commit rule — CLAUDE.md now requires a
git commit save point before any code changes. (File: CLAUDE.md)
- Added Post-Build Quality Gate — 6-step verification after every code change: simplify x2, math check x2, function test x2, import check, type check, integration check. (File:
CLAUDE.md)
- Removed startup proposal check — No longer auto-checks
/home/ubuntu/shared/proposals/ on session start. (File: CLAUDE.md)
- Removed tmux auto-attach from .bashrc — New SSH tabs now get a fresh shell instead of attaching to the main tmux session. (File:
~/.bashrc)
EcoCell
- Added Pre-Session Commit rule — Same as EdgeClaw. (File:
CLAUDE.md)
- Added Post-Build Quality Gate — Same as EdgeClaw. (File:
CLAUDE.md)
2026-04-14
EcoCell
- Companion check-in cleanup (5 bugs) — Activation status now updates the on-screen badge after IMEI #2 parses ("Unactivated"/"FactoryActivated" → "Activated" or "N/A" at source), color/storage parser tightened with SickW #92 fallback + color-code map (BLK/WHT/BLU/SLV/ORG/etc.), shared
normalizeCarrier helper called on USB connect AND in check-in (no more raw "US Verizon LTE Unlocked Policy" reaching DB), batch check-in now sequential with real per-device error messages (was silently swallowing err.message), server-side normalizeCarrier safety net added. (Files: companion-inject.js, python/usb_service.py, server/routes/usb-reader.js)
Source: ~/edgeclaw/docs/changelog.md