Changelog

What ships, when. Every notable update on SPLAT lives here.

    v1.1.24

    Fixed
    • Head block poll was hammering a single RPC node at 5 req/s (200ms interval), triggering HTTP 429 "Too many requests" that intermittently broke the head block cache and collaterally disabled the witness schedule cache — silently turning off witness-aware broadcast; the poll now round-robins across the top-5 ranked nodes (~1 req/s/node, well under the rate limit) so both caches stay fresh
    • Witness schedule poll now round-robins across the node pool independently of the head block poll, so a 429 on one node no longer stalls witness-aware broadcast until the next 10s tick
    Changed
    • Buy eligibility wait now uses an effective head block number that merges the polled snapshot with a real-time counter fed by the blockchain stream (0 extra RPC), keeping N+2 detection responsive even when every polled node returns 429 in a burst
    • Block position diagnostic log now includes the listing-to-buy block offset, distinguishing a low intra-block position in the correct N+3 block from a late landing in N+4+ where a competitor already won

    v1.1.23

    Fixed
    • Witness-aware broadcast was silently disabled on the fast buy path: the predicted target block used the stale pre-sign ref_block_number (signed before the eligibility wait) instead of the current head, so the witness prediction always returned null and the fanout never targeted the producing witness — now targets head+1, activating the intended low block position on ~43% of blocks where the witness runs a public RPC

    v1.1.22

    Changed
    • Head block poll interval reduced from 1s to 200ms with an overlap guard, cutting the block-aware wait cache lag by ~300ms so buys fire earlier in the 3s block window for a lower block position

    v1.1.21

    Added
    • Witness-aware broadcast: the buy fanout now targets the RPC of the predicted block-producing witness in priority, landing the transaction at the head of its mempool and improving block position against competing bots (covers ~43% of blocks where the witness runs a public RPC; falls back to the normal fanout otherwise with no regression)

    v1.1.20

    Added
    • Offline forensic script (analyze-l2) classifies Layer 2 buy failures by root cause (competitor won, parent listing invalid, authority revoked, timeout) and reports competitor accounts with block-position latency gaps, replacing the manual hivehub.dev investigation
    Fixed
    • Listings priced below 0.01 USD are now filtered at the blockchain stream source, preventing buy broadcasts on listings that Splinterlands Layer 2 rejects and saving wasted broadcasts, L2 verification polls and Discord noise

    v1.1.19

    Fixed
    • Periodic posting-authority refresh job now detects on-chain authority revocations that were not reflected in the database, preventing the pipeline from assigning deals to users who had revoked @phanty's purchase authority
    • Deal assignment no longer selects posting-authority configs whose buy authority flag has been revoked, short-circuiting them before L2 verification fails

    v1.1.18

    Changed
    • Block-aware broadcast timing targets block N+3 precisely by tracking the Hive head block, eliminating 3-block eligibility errors
    • Pre-signed transactions remove ~150-300ms of RPC and signing latency from the buy broadcast hot path
    • Head block cache service polls Hive every 1s to enable precise block-aware timing and cached transaction signing
    • Critical timing anomalies (block-aware wait timeout, tx near expiry) now send Discord alerts via DISCORD_WEBHOOK_ERROR

    v1.1.17

    Changed
    • Removed pipeline-stage Discord diagnostics (DETECTED/PRE-ASSIGN/POST-ASSIGN/ASSIGNED/PRIORITIZED/PRE-BROADCAST/BROADCAST-OK/L2-OK/L2-FAIL) to reduce hot-path I/O and memory pressure during deal processing

    v1.1.16

    Fixed
    • Fixed Strategy Advisor crash when computing the premium-zone price threshold: PostgreSQL PERCENTILE_CONT expects a 0-1 fraction, not a 0-100 percentile value

    v1.1.15

    Changed
    • Strategy Advisor now aligns recommended profiles with the parameters of the top-performing real configs (tier, minimal gain, discount threshold) instead of anonymous global deal percentiles
    • Added a 4th 'Low Competition' profile that targets expensive, under-traded cards to break out of the saturated sub-$1 zone
    • Recommended configs now carry the tier (Standard/Pro/Max) observed in the most profitable real configs, instead of always defaulting to Standard

    v1.1.14

    Changed
    • Something secret

    v1.1.13

    Changed
    • Deal assignment no longer sends a Discord webhook when a user is skipped for insufficient balance; the skip is still logged locally, removing spam from users positioned on many deals with a low balance

    v1.1.12

    Fixed
    • Reverted Layer 2 verification retry window that was too short (1s/5 attempts/500ms = ~3.5s) and caused almost all purchases to fail with 'Transaction not found' since Splinterlands L2 indexing needs 3-9s (1-3 Hive blocks); restored a ~20s window (3s initial + 8 attempts × 2.5s) while keeping the 5s HTTP timeout so the hot path is not blocked
    • Removed the per-purchase L2 override in the timed-buy path that forced the same too-short window, so timed buys now use the sane default retry window

    v1.1.11

    Changed
    • Purchased deals are now re-listed in parallel instead of sequentially, cutting multi-card deal relisting latency from N times ~20s down to a single ~20s window
    • Cashback transfers and user stats updates now run in the background after relisting instead of blocking the sell pipeline, decoupling bookkeeping from the trading hot path
    • Layer 2 verification timeouts and retry delays have been tightened across the board (HTTP timeout 20s to 5s, initial delay 3s to 1s, retry delay 2s to 500ms, max attempts 10 to 5), reducing worst-case L2 verification from over 200s down to under 30s
    • Per-user config and user lookups on the buy path are now fetched in two batched queries instead of two queries per assigned user, removing DB round-trip scaling with the number of assigned users
    • User collection fetch timeout lowered from 15s to 8s to reduce hot-path stall on slow Splinterlands API responses
    Fixed
    • Sell market id retrieval after a successful listing now runs fire-and-forget instead of blocking the sell flow for up to 15s on a full collection refetch; the id is recovered by the next auto-reprice or deal sync cycle if the background fetch fails
    • Backend now handles SIGTERM gracefully on Railway shutdown, flushing buffered analytics events and closing the HTTP server cleanly instead of being killed mid-flush and losing up to 100 events

    v1.1.10

    Changed
    • Market reference prices now rebuild into a fresh map and swap atomically instead of clearing in place, eliminating the 1-3 second window every 5 minutes where all deals were missed because the price map was transiently empty
    • Splintertrendz cache now follows a push model: the poller updates the in-memory map directly after each fetch, and the trading hot path no longer performs a 4.9MB synchronous file read that blocked the event loop for 20-50ms
    • Deal assignment triggered from the blockchain stream now runs fire-and-forget instead of blocking stream consumption, cutting 50-200ms of stall per inserted deal; a reentrancy guard prevents concurrent cycles from stacking
    • Pipeline diagnostic Discord messages are now buffered and flushed in a single webhook every 5 seconds instead of one webhook per stage per deal, cutting Discord socket saturation from 30+ messages per hour to a few batches
    • Card name lookup on the detection hot path now uses a synchronous accessor instead of an awaited cache call, removing an unnecessary microtask hop per detected deal
    Fixed
    • Listings with unparseable UIDs are now skipped immediately with a warning instead of blocking the blockchain stream for up to 15 seconds on an HTTP fallback that rarely succeeds
    • Market state refresh is now reentrancy-guarded so the periodic 5-minute refresh cannot overlap a previous in-flight refresh and corrupt the price map
    • Splintertrendz cache is warmed from the persisted JSON file at startup before the blockchain stream starts, so deals requiring the Splintertrendz check are no longer systematically rejected for the first 20-60 seconds after a restart while the first API fetch completes
    • Pipeline start timing is now marked once per Hive transaction instead of once per listing within the transaction, removing redundant map writes on multi-listing transactions

    v1.1.9

    Changed
    • Database connection pool raised from 5 to 10 and made configurable via the DB_POOL_SIZE environment variable, eliminating connection contention between the trading hot path, background jobs and admin metrics endpoints
    Fixed
    • Added database indexes on Config (active_config/active_trading/user_id and user_id/active_config/updated_at) which had none and was full-scanned on every trading cycle (assignment, balance enforcement, auto-reprice, initialization)
    • Added GIN indexes on DetectedDeal.card_market_id and assigned_to to speed up deal deduplication on the detection hot path and the assignment query that runs every cycle
    • Added indexes on Deal.buy_date, sell_date and updated_at plus composites (user_id,state) and (origin,user_id) to eliminate full-table scans on chart, strategy advisor and admin stats queries as the Deal table grows
    • Added a covering partial index on sold deals to turn admin and public stats profit aggregations into index-only scans
    • Added a GIN index on User.referred_user to speed up referrer lookup on every successful purchase

    v1.1.8

    Fixed
    • Backend now self-restarts cleanly (exit 0) when process RSS exceeds 500MB, letting Railway spin up a fresh container instead of waiting for a brutal OOM-kill; clears V8 fragmentation and kernel socket buffers that the periodic GC cannot reclaim

    v1.1.7

    Fixed
    • Scheduled explicit garbage collection every 10 minutes with --expose-gc to compact V8 old space and release unused pages back to the OS, countering the slow RSS creep caused by blockchain stream allocation churn

    v1.1.6

    Changed
    • Public stats and competition endpoints now serve a 60-second in-memory cache, eliminating repeated full-table aggregations polled every minute by the frontend
    Fixed
    • Added database indexes on Deal.origin and Deal.profit_percentage to speed up admin user-stats and best-deals queries as the Deal table grows
    • Analytics events are now buffered and inserted in batches every 5 seconds instead of one INSERT per event, reducing connection-pool pressure

    v1.1.5

    Changed
    • Balance enforcement now runs every 5 minutes instead of every minute (balance drift is slow and buys already deduct the in-memory cache optimistically)
    • Database connection pool raised from 2 to 5 to avoid contention between background jobs and the trading hot path
    • Balance enforcement now fetches user balances in bounded parallel batches and writes balance updates in a single transaction instead of one HTTP call and one write per user
    Fixed
    • Added a database index on DetectedDeal.expiration, speeding up both the expired-deal cleanup job and the deal assignment query on the trading hot path

    v1.1.4

    Fixed
    • Discord webhook and error logger now consume HTTP response bodies so keep-alive sockets are released, fixing a slow native-memory leak that caused RSS to climb over time
    • Global HTTP pool (undici) tightened to 1s keep-alive and 10 concurrent sockets per origin to cap native socket memory
    • Blockchain stream only rotates Hive node after 3 consecutive failures instead of on every reconnect, reducing client churn and connection allocation
    • Pipeline timing, listing timing and pending L2 check buffers are now visible in memory snapshots for leak diagnosis

    v1.1.3

    Changed
    • Backend server and worker now run in a single Node process to cut baseline memory usage (~100MB less RAM, one Railway service instead of two)
    • Market reference prices refresh every 5 minutes instead of every minute (the blockchain stream keeps them up to date in real time)
    • Prisma connection pool reduced to 2 and V8 heap capped to lower peak memory
    Fixed
    • Detected deals endpoint no longer loads the entire table into memory (now bounded to live, recent entries)
    • Per-user deal and auto-reprice listings are now bounded to prevent unbounded memory spikes

    v1.1.2

    Security
    • Splintertrends price check is now defensive: deals are rejected when the reference cache is unavailable, the card is missing from the cache, or the relevant price field is 0. Previously such deals were validated by default.

    v1.1.1

    Added
    • Toggle 'Exclude bots' on the admin analytics dashboard to filter bots out of the device breakdown chart

    v1.1.0

    Added
    • Anonymous client-side analytics tracking (cookieless, no PII stored, hash-based visitor IDs with 24h rotation)
    • Admin analytics dashboard at /admin/analytics with top pages, wizard funnel drop-off, events summary (success/fail), and device breakdown
    • 90-day rolling retention for analytics events with automatic purge

    v1.0.0

    Changed
    • Synchronize feature is now restricted to VIP+ users (vip/admin/superadmin)
    • Synchronization is now limited to cards currently listed on a marketplace (Splinterlands or third-party); existing purchased deals are atomically transitioned to listed when detected

    v0.0.0

    Notes
    • Everything that happened before this line was either pure genius or a happy accident. We'll never know.