Home v3.1

Changelog

Product updates, feature additions, performance optimizations, and fixes to HL Vaults.

111 releases Latest Sep 2, 2026
Latest
#01

Custom Screen Shadowing

  • # Custom screen shadowing fix
  • Fixed saving a named screen whose id collides with a built-in screen (e.g. "my-vaults" collides with the built-in My Vaults preset): the built-in was applied instead of the just-saved custom screen, dropping the user's filters (vault-name exclusion) and injecting the preset's sort.
  • Made user-created screens win on id collisions in the screen manager: getAllScreens() now returns custom screens before built-ins, so applyScreenById / getActiveScreen / isScreenModifiedBy resolve to the custom screen.
  • Made getScreenById (URL reload path for filters and vault types) prefer custom screens over built-ins on id collisions.
  • Guarded detachBuiltInIfModified so a custom screen shadowing a built-in id is never detached as a built-in when modified.
  • Hid built-in screens shadowed by a custom screen with the same id in the ScreenSelector dropdown to avoid duplicate entries.
  • Added src/lib/grid/screens.spec.ts covering collision resolution, apply-by-id, and the detach guard.
#06

Phase 04 Tests Guard Docs

  • # Phase 04 — tests, guard, docs
  • Added cli/src/detail.parity.spec.ts — seeds a fixture file-backed PGlite and pins hlvaults detail <addr> (getVaultDataList with DETAIL_COLUMN_IDS → buildVaultDetailRows) to the web Details tab: computed leverage/bias/grades, user columns with and without --wallet, and the not-found empty-rows path.
  • Extended the eslint purity-guard block in eslint.config.js from the Phase 01 core to the full CLI closure (vault/details, page/column-templates, utils, hardcoded, sync engines, and their pure transitive helpers), so npm run lint guards every module the CLI shares.
  • Added src/lib/db/purity-guard.spec.ts — parses the core-module list out of eslint.config.js (single source of truth) and scans each file for forbidden browser-only imports and globals ($app, svelte, .svelte, browser DB/state modules, window/navigator/document/localStorage/SharedWorker/BroadcastChannel), allowing type-only imports.
  • Updated AGENTS.md directory tree with cli/, src/lib/db/db-interface.ts / node-db.ts / migration-core.ts, src/lib/sync/, and added a SQL-vs-TS split section (data-math in get_vault_listing, presentation in TS).
  • Updated README.md with a Local CLI section (usage, parity contract, JSON/machine mode, exit codes, Vite-vs-bun decision) and fixed the stale npm test description.
  • Marked Phase 04 done in roadmap/master.md.
#05

Phase 02 Formula Fields to Sql

  • Added get_vault_listing(p_user_address, p_config) in sql/src/0100-functions/get_vault_listing.sql: every vault_master_view column (including all_time_max_drawdown) + user columns + the data-math fields (leader/depositor annualized performance, numeric current_leverage, bias/exposures/position_count from the relational vault_asset_positions table, last_fill_time), replicating the old TS loop semantics in float8.
  • Added idempotent migration sql/migrations/0.4.0.sql and regenerated sql/db.generated.sql via make generate-db (web app surfaces the 0.4.0 update toast on next boot).
  • Rewired getVaultDataList to SELECT ... FROM get_vault_listing($1, $2::jsonb) v, deleted the TS post-processing loop, and made every row carry the formula fields regardless of the requested columns (alerts, the tag evaluator, and portfolio exposure stats depend on them); re-pointed vault-columns.ts column/filter expressions at the function's output, adding the missing leader_performance/depositor_performance mappings.
  • Switched current_leverage to a numeric ratio everywhere: added formatLeverage()/computeLeverageRatio() in src/lib/vault/metrics.ts, formatted N.Nx at the display sites (LeverageCell.svelte, details.ts, WalletAllocationTable.svelte), and aligned WalletAllocationRow with the numeric VaultData type.
  • Added the Phase 02 parity safety net src/lib/db/vault-queries.spec.ts: in-memory PGlite seeded through createNodeDb, fixtures for zero-size positions, empty books, exactly-at-threshold bias, missing depositors, account value <= 0, plus explicit-columns, minimal-columns, and SQL-side user-filter paths.
  • All gates green: npm run check (0 errors/0 warnings), npm run lint clean, npm test 790/790 across 63 files, npm run build succeeds.
#04

Wallet Sync Extraction

  • Added src/lib/sync/wallet-sync.ts — the shared, browser-free tracked-wallet sync engine: syncUserWallet(address, options) fetches userVaultEquities, writes via update_user_vault_equities (exit watermarking), then re-syncs each active vault wallet-scoped, with per-vault failure isolation, onStart/onProgress callbacks, and a { equities, activeVaults, synced, failed } result.
  • Thinned syncUserData in src/lib/vault-store.svelte.ts to UI concerns only: it delegates all DB/API work to syncUserWallet and keeps the message buffer, store refreshes, and db-updated broadcast; export name/signature unchanged. All sync message strings preserved byte-for-byte (per-vault outcome rides an optional error 4th arg on onProgress).
  • Added src/lib/sync/wallet-sync.spec.ts parity fixture on a Node file-backed PGlite with stubbed Hyperliquid fetches: pins user_vault_equities population, the exited_at watermark (zeroed equity + preserved all_time_pnl), per-vault failure isolation, and the excludeAddress sync-ordering contract (excluded global import keeps wallet rows absent, wallet sync writes them, no-exclusion global-after-wallet clobbers them).
  • No schema changes, no migrations, no hardcoded.ts changes; the eslint purity guard already covered src/lib/sync/**.
  • Roadmap: master status for Phase 01.5 set to In progress pending the user's gate run (check/lint/test/build).
#03

Phase 15 Tracked Wallet Sync

  • Added roadmap/phase-15-tracked-wallet-sync.md to extract the tracked-wallet (user) sync engine into shared, Node-safe code — the prerequisite for CLI access to a tracked wallet's progress, user vault equities, and the leaderboard.
  • Swept Phase 01.5 into roadmap/master.md: new status row, context decision, key file reference, working instruction, and out-of-scope update (user vault equities + leaderboard are now served by the shared engines, with CLI commands deferred to Phase 03).
  • Resolved scope contradictions: updated phase-03-cli-package.md (constraint no longer forbids user-equity sync; added the sync-ordering note) and phase-04-tests-guard-docs.md (out-of-scope list now matches master).
  • Documented the sync-ordering contract in phase-15: global sync must pass the tracked wallet as excludeAddress before wallet sync runs, pinned by an excludeAddress parity fixture.
  • Verified against the live Hyperliquid API and the real sync payload that follower data rides the global payload, the wallet-scoped details call returns the tracked wallet's row beyond follower-position caps, and the existing eslint purity guard already covers src/lib/sync/**.
#02

Extract Reusable Core

  • Extracted a platform-agnostic DB adapter: type-only DbHandle/DbTx interfaces, a Node file-backed PGlite singleton (node-db.ts), and a platform switch in database.ts so the browser SharedWorker proxy and Node share the exact same query layer. The node adapter is loaded lazily so PGlite never enters the browser main-thread bundle.
  • Moved the migration runner (ledger bootstrap, status, apply, seed) from the SharedWorker into a pure migration-core.ts that takes a { version, sql }[] list; the worker keeps its import.meta.glob loader and the CLI will supply an fs loader.
  • Extracted a browser-free sync engine (src/lib/sync/vault-sync.ts) with buildSyncPayloadUrl, fetchGlobalSyncPayload, syncGlobalVaults, syncVaultDetails, syncVaultHistory, and isVaultOutdated; vault-store.svelte.ts now only orchestrates locks, leader election, intervals, broadcast, and storage and delegates the work.
  • Parameterized refreshVaultData with explicit filters/wallet/columns and extracted the computed-filter post-pass into a pure shared applyComputedFilters so the CLI can reuse it without runes state; decoupled getVaultDataList from column-state by importing pure vault-columns helpers and accepting an injectable perfConfig.
  • Made tag and built-in-screen loaders injectable (defaulting to import.meta.glob) so the CLI can supply fs-based loaders.
  • Added a purity guard to eslint (no-restricted-imports + no-restricted-globals) preventing the core modules from importing $app, Svelte, .svelte files, or browser-only globals/modules, and moved the CLI data-dir default into hardcoded.ts.
  • Added a Node smoke test that opens a file-backed PGlite, loads the generated schema, inserts a fixture, and runs getVaultDataList to prove the shared query layer works in Node.
#01

Cli Package

  • Implemented the Phase 03 cli/ package — a local-only hlvaults CLI reusing the shared sync + query engines.
  • Added cli/ with a Vite SSR build (cli/vite.config.ts resolves $lib/$sql aliases, ?raw, and import.meta.glob), bin hlvaults, and root scripts cli:build / cli:dev plus a make cli-build target.
  • Implemented the command surface: detail (web Details-tab parity via DETAIL_COLUMN_IDS + buildVaultDetailRows, --wallet override, not-found path with on-demand sync), sync (sync-ordering contract enforced inside: global with excludeAddress before syncUserWallet), status, sql (argument, stdin -, and TTY REPL), wallet track/untrack/show/sync, reset (--yes, --dry-run, --keep-wallets), plus self-describing schema and columns detail commands.
  • Added the two-mode output contract: stdout is data (JSON envelopes with meta), stderr is narration; machine mode engages on --json, non-TTY stdout, or HLVAULTS_NON_INTERACTIVE=1; stable exit codes 0/1/2/3/4/5 with machine-readable error hints.
  • Added the migration gate with web parity: fresh installs apply db.generated.sql and seed the ledger silently; existing DBs prompt (human) or exit 3 with a --migrate hint (machine) — commands never run against a stale schema.
  • Verified against the live sync API: 437-vault global import, per-vault detail/history sync, tracked-wallet user columns populated via --wallet, reset-to-blank-slate with fresh-install re-seed, and 6 cli/src/render.spec.ts unit tests passing.
  • Hardened after adversarial review: routed the shared engines' console.log narration to stderr so machine-mode stdout is byte-pure JSON (the web build strips console via terser, which hid this), added a PID lockfile (PGlite is officially single-connection per data dir — concurrent processes now exit 4 with a hint), switched schema row counts from pg_stat_user_tables estimates to exact count(*), fixed cli:build to preserve the bin's exec bit, and reported on-demand syncs in meta.syncedThisRun.
#01

Vault Details Tab

  • Added a Details tab at the end of the vault detail page tabs.
  • Added a transposed table showing every vault listing column, with header names matching the grid display names (abbr ?? label).
  • Added getVaultDataList vaultAddress option to load a single vault's listing row with computed and user-scoped fields.
  • Added details.svelte controller wiring the listing row through getVaultDataList and reloading on vault-updated broadcasts.
  • Added privacy masking and tag chips to the Details value cells, plus a pure buildVaultDetailRows formatter with unit tests.
#01

Alert Cagr Condition

  • Added CAGR (User UPnL CAGR) as a new trigger condition in the alert feature.
  • Added cagr condition type mapping to user_upnl_pct_cagr in src/lib/alerts/alerts.ts.
  • Added user_upnl_pct_cagr to the alert column selection so CAGR evaluates on every row.
  • Added spec coverage for the CAGR condition pass/fail evaluation.
#01

Global Sync Stale Equity Fix

  • Fix Global Sync overwriting User Sync's fresh equity data
  • Investigated stale equity column after vault withdrawal: traced to a race condition where Global Sync's batch import overwrites User Sync's correct zeroed equity with stale data from the sync API
  • Added excludeAddress parameter to bulkImportVaults in queries.ts that strips the tracked/connected wallet from the sync API's followers array before building the SQL INSERT
  • Updated runGlobalSync in vault-store.svelte.ts to pass walletState.address as the excludeAddress, ensuring only User Sync (which has fresh per-user data from Hyperliquid) manages that wallet's vault_user_info rows
Showing 1–10 of 111 entries
1 / 12

This site stores data locally in your browser for essential functionality — vault data, preferences, and settings are saved via localStorage and IndexedDB. We also use cookies and similar technologies for analytics and preference remembrance. You can accept or reject non-essential cookies. Learn more.