dexbot 1.6.5 → 1.6.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (228) hide show
  1. package/CHANGELOG.md +76 -4
  2. package/README.md +108 -36
  3. package/analysis/README.md +11 -16
  4. package/analysis/account_resolver.ts +1 -11
  5. package/analysis/bot_usage/kibana_bot_queries.ts +1 -1
  6. package/analysis/chain_pool.ts +1 -1
  7. package/analysis/fills_source.ts +0 -6
  8. package/analysis/grid_correction_check.ts +20 -26
  9. package/analysis/resolve_source.ts +1 -1
  10. package/analysis/trade_profitability.ts +2 -5
  11. package/analysis/trend_detection/README.md +1 -3
  12. package/analysis/trend_detection/package.json +1 -1
  13. package/claw/package.json +1 -1
  14. package/claw/runtimes/openclaw-plugin/openclaw.plugin.json +1 -1
  15. package/claw/runtimes/openclaw-plugin/package.json +1 -1
  16. package/claw/tests/test_claw_mcp_transport.ts +2 -2
  17. package/dist/analysis/account_resolver.d.ts +1 -4
  18. package/dist/analysis/account_resolver.d.ts.map +1 -1
  19. package/dist/analysis/account_resolver.js +1 -1
  20. package/dist/analysis/account_resolver.js.map +1 -1
  21. package/dist/analysis/bot_usage/kibana_bot_queries.d.ts +1 -2
  22. package/dist/analysis/bot_usage/kibana_bot_queries.d.ts.map +1 -1
  23. package/dist/analysis/bot_usage/kibana_bot_queries.js +1 -1
  24. package/dist/analysis/bot_usage/kibana_bot_queries.js.map +1 -1
  25. package/dist/analysis/chain_pool.d.ts +1 -3
  26. package/dist/analysis/chain_pool.d.ts.map +1 -1
  27. package/dist/analysis/chain_pool.js +1 -1
  28. package/dist/analysis/chain_pool.js.map +1 -1
  29. package/dist/analysis/fills_source.d.ts +1 -51
  30. package/dist/analysis/fills_source.d.ts.map +1 -1
  31. package/dist/analysis/fills_source.js +1 -1
  32. package/dist/analysis/fills_source.js.map +1 -1
  33. package/dist/analysis/grid_correction_check.d.ts +2 -3
  34. package/dist/analysis/grid_correction_check.d.ts.map +1 -1
  35. package/dist/analysis/grid_correction_check.js +18 -26
  36. package/dist/analysis/grid_correction_check.js.map +1 -1
  37. package/dist/analysis/resolve_source.d.ts +1 -1
  38. package/dist/analysis/resolve_source.d.ts.map +1 -1
  39. package/dist/analysis/trade_profitability.d.ts.map +1 -1
  40. package/dist/analysis/trade_profitability.js +2 -7
  41. package/dist/analysis/trade_profitability.js.map +1 -1
  42. package/dist/dexbot.d.ts.map +1 -1
  43. package/dist/dexbot.js +82 -83
  44. package/dist/dexbot.js.map +1 -1
  45. package/dist/market_adapter/core/kibana_candles.d.ts +1 -15
  46. package/dist/market_adapter/core/kibana_candles.d.ts.map +1 -1
  47. package/dist/market_adapter/core/kibana_candles.js +1 -1
  48. package/dist/market_adapter/core/kibana_candles.js.map +1 -1
  49. package/dist/market_adapter/inputs/fetch_lp_data.d.ts +1 -35
  50. package/dist/market_adapter/inputs/fetch_lp_data.d.ts.map +1 -1
  51. package/dist/market_adapter/inputs/fetch_lp_data.js +10 -54
  52. package/dist/market_adapter/inputs/fetch_lp_data.js.map +1 -1
  53. package/dist/market_adapter/inputs/kibana_feed_source.d.ts +1 -8
  54. package/dist/market_adapter/inputs/kibana_feed_source.d.ts.map +1 -1
  55. package/dist/market_adapter/inputs/kibana_feed_source.js +1 -1
  56. package/dist/market_adapter/inputs/kibana_feed_source.js.map +1 -1
  57. package/dist/market_adapter/inputs/window_cache.d.ts +2 -63
  58. package/dist/market_adapter/inputs/window_cache.d.ts.map +1 -1
  59. package/dist/market_adapter/inputs/window_cache.js +22 -102
  60. package/dist/market_adapter/inputs/window_cache.js.map +1 -1
  61. package/dist/modules/account_bots.d.ts +16 -2
  62. package/dist/modules/account_bots.d.ts.map +1 -1
  63. package/dist/modules/account_bots.js +108 -44
  64. package/dist/modules/account_bots.js.map +1 -1
  65. package/dist/modules/account_orders.d.ts +20 -2
  66. package/dist/modules/account_orders.d.ts.map +1 -1
  67. package/dist/modules/account_orders.js +63 -3
  68. package/dist/modules/account_orders.js.map +1 -1
  69. package/dist/modules/bitshares-native/chain_client.d.ts +10 -0
  70. package/dist/modules/bitshares-native/chain_client.d.ts.map +1 -1
  71. package/dist/modules/bitshares-native/chain_client.js +197 -28
  72. package/dist/modules/bitshares-native/chain_client.js.map +1 -1
  73. package/dist/modules/bitshares-native/crypto/ecc.browser.d.ts.map +1 -1
  74. package/dist/modules/bitshares-native/crypto/ecc.browser.js +0 -31
  75. package/dist/modules/bitshares-native/crypto/ecc.browser.js.map +1 -1
  76. package/dist/modules/bitshares-native/subscriptions.d.ts.map +1 -1
  77. package/dist/modules/bitshares-native/subscriptions.js +312 -10
  78. package/dist/modules/bitshares-native/subscriptions.js.map +1 -1
  79. package/dist/modules/bitshares-native/transport.d.ts +1 -0
  80. package/dist/modules/bitshares-native/transport.d.ts.map +1 -1
  81. package/dist/modules/bitshares-native/transport.js +97 -3
  82. package/dist/modules/bitshares-native/transport.js.map +1 -1
  83. package/dist/modules/bitshares_client.d.ts +20 -0
  84. package/dist/modules/bitshares_client.d.ts.map +1 -1
  85. package/dist/modules/bitshares_client.js +29 -0
  86. package/dist/modules/bitshares_client.js.map +1 -1
  87. package/dist/modules/chain_keys.d.ts +37 -22
  88. package/dist/modules/chain_keys.d.ts.map +1 -1
  89. package/dist/modules/chain_keys.js +145 -44
  90. package/dist/modules/chain_keys.js.map +1 -1
  91. package/dist/modules/cli_start_onboarding.d.ts +10 -0
  92. package/dist/modules/cli_start_onboarding.d.ts.map +1 -0
  93. package/dist/modules/cli_start_onboarding.js +15 -0
  94. package/dist/modules/cli_start_onboarding.js.map +1 -0
  95. package/dist/modules/cli_start_output.d.ts +6 -0
  96. package/dist/modules/cli_start_output.d.ts.map +1 -0
  97. package/dist/modules/cli_start_output.js +8 -0
  98. package/dist/modules/cli_start_output.js.map +1 -0
  99. package/dist/modules/constants.d.ts +13 -0
  100. package/dist/modules/constants.d.ts.map +1 -1
  101. package/dist/modules/constants.js +103 -1
  102. package/dist/modules/constants.js.map +1 -1
  103. package/dist/modules/credit_runtime.d.ts +0 -2
  104. package/dist/modules/credit_runtime.d.ts.map +1 -1
  105. package/dist/modules/credit_runtime.js +1 -10
  106. package/dist/modules/credit_runtime.js.map +1 -1
  107. package/dist/modules/dexbot_class.d.ts +13 -10
  108. package/dist/modules/dexbot_class.d.ts.map +1 -1
  109. package/dist/modules/dexbot_class.js +0 -9
  110. package/dist/modules/dexbot_class.js.map +1 -1
  111. package/dist/modules/dexbot_cow_runtime.d.ts +13 -0
  112. package/dist/modules/dexbot_cow_runtime.d.ts.map +1 -1
  113. package/dist/modules/dexbot_cow_runtime.js +62 -10
  114. package/dist/modules/dexbot_cow_runtime.js.map +1 -1
  115. package/dist/modules/dexbot_fill_runtime.d.ts +6 -1
  116. package/dist/modules/dexbot_fill_runtime.d.ts.map +1 -1
  117. package/dist/modules/dexbot_fill_runtime.js +22 -3
  118. package/dist/modules/dexbot_fill_runtime.js.map +1 -1
  119. package/dist/modules/dexbot_maintenance_runtime.d.ts +24 -1
  120. package/dist/modules/dexbot_maintenance_runtime.d.ts.map +1 -1
  121. package/dist/modules/dexbot_maintenance_runtime.js +45 -1
  122. package/dist/modules/dexbot_maintenance_runtime.js.map +1 -1
  123. package/dist/modules/dexbot_state_recovery.d.ts.map +1 -1
  124. package/dist/modules/dexbot_state_recovery.js +13 -1
  125. package/dist/modules/dexbot_state_recovery.js.map +1 -1
  126. package/dist/modules/order/accounting.d.ts +4 -18
  127. package/dist/modules/order/accounting.d.ts.map +1 -1
  128. package/dist/modules/order/accounting.js +4 -34
  129. package/dist/modules/order/accounting.js.map +1 -1
  130. package/dist/modules/order/export.d.ts +9 -12
  131. package/dist/modules/order/export.d.ts.map +1 -1
  132. package/dist/modules/order/export.js +9 -12
  133. package/dist/modules/order/export.js.map +1 -1
  134. package/dist/modules/order/grid.d.ts +35 -40
  135. package/dist/modules/order/grid.d.ts.map +1 -1
  136. package/dist/modules/order/grid.js +76 -44
  137. package/dist/modules/order/grid.js.map +1 -1
  138. package/dist/modules/order/grid_reconcile.d.ts.map +1 -1
  139. package/dist/modules/order/grid_reconcile.js +111 -20
  140. package/dist/modules/order/grid_reconcile.js.map +1 -1
  141. package/dist/modules/order/grid_reconcile_internal.d.ts +5 -3
  142. package/dist/modules/order/grid_reconcile_internal.d.ts.map +1 -1
  143. package/dist/modules/order/grid_reconcile_internal.js +29 -3
  144. package/dist/modules/order/grid_reconcile_internal.js.map +1 -1
  145. package/dist/modules/order/logger.d.ts +12 -2
  146. package/dist/modules/order/logger.d.ts.map +1 -1
  147. package/dist/modules/order/logger.js +29 -7
  148. package/dist/modules/order/logger.js.map +1 -1
  149. package/dist/modules/order/manager.d.ts +49 -8
  150. package/dist/modules/order/manager.d.ts.map +1 -1
  151. package/dist/modules/order/manager.js +72 -34
  152. package/dist/modules/order/manager.js.map +1 -1
  153. package/dist/modules/order/utils/order.d.ts +22 -7
  154. package/dist/modules/order/utils/order.d.ts.map +1 -1
  155. package/dist/modules/order/utils/order.js +200 -33
  156. package/dist/modules/order/utils/order.js.map +1 -1
  157. package/dist/modules/order/utils/system.d.ts +97 -0
  158. package/dist/modules/order/utils/system.d.ts.map +1 -1
  159. package/dist/modules/order/utils/system.js +274 -2
  160. package/dist/modules/order/utils/system.js.map +1 -1
  161. package/dist/modules/order/utils/withPoolRef.d.ts +12 -0
  162. package/dist/modules/order/utils/withPoolRef.d.ts.map +1 -1
  163. package/dist/modules/order/utils/withPoolRef.js +17 -0
  164. package/dist/modules/order/utils/withPoolRef.js.map +1 -1
  165. package/dist/modules/order/working_grid.d.ts +8 -13
  166. package/dist/modules/order/working_grid.d.ts.map +1 -1
  167. package/dist/modules/order/working_grid.js +8 -29
  168. package/dist/modules/order/working_grid.js.map +1 -1
  169. package/dist/modules/paths.d.ts +7 -1
  170. package/dist/modules/paths.d.ts.map +1 -1
  171. package/dist/modules/paths.js +10 -3
  172. package/dist/modules/paths.js.map +1 -1
  173. package/dist/modules/utils/text_width.d.ts +19 -0
  174. package/dist/modules/utils/text_width.d.ts.map +1 -0
  175. package/dist/modules/utils/text_width.js +97 -0
  176. package/dist/modules/utils/text_width.js.map +1 -0
  177. package/dist/pm2.d.ts.map +1 -1
  178. package/dist/pm2.js +95 -18
  179. package/dist/pm2.js.map +1 -1
  180. package/dist/scripts/sync-version.js +0 -22
  181. package/dist/scripts/sync-version.js.map +1 -1
  182. package/dist/scripts/update.js +62 -13
  183. package/dist/scripts/update.js.map +1 -1
  184. package/dist/scripts/update_dist_freshness.d.ts +12 -0
  185. package/dist/scripts/update_dist_freshness.d.ts.map +1 -1
  186. package/dist/scripts/update_dist_freshness.js +30 -1
  187. package/dist/scripts/update_dist_freshness.js.map +1 -1
  188. package/dist/unlock.d.ts +14 -2
  189. package/dist/unlock.d.ts.map +1 -1
  190. package/dist/unlock.js +73 -4
  191. package/dist/unlock.js.map +1 -1
  192. package/docs/BITSHARES_ONBOARDING.md +9 -6
  193. package/docs/COW_INVARIANTS.md +9 -0
  194. package/docs/CREDENTIAL_SECURITY.md +26 -0
  195. package/docs/DEXBOT_COMPARISON.md +11 -11
  196. package/docs/EVOLUTION.md +9 -7
  197. package/docs/FUND_MOVEMENT_AND_ACCOUNTING.md +1 -1
  198. package/docs/GRID_PRICE_INVARIANT.md +573 -0
  199. package/docs/GRID_RECALCULATION.md +1 -1
  200. package/docs/GRID_RECONCILE.md +60 -39
  201. package/docs/LOGGING.md +17 -2
  202. package/docs/ORDER_ENGINE_POST_1.0_RETROSPECTIVE.md +555 -0
  203. package/docs/README.md +3 -3
  204. package/docs/WORKFLOW.md +12 -6
  205. package/docs/architecture.md +40 -38
  206. package/docs/developer_guide.md +4 -8
  207. package/market_adapter/README.md +16 -12
  208. package/modules/README.md +1 -1
  209. package/package.json +8 -4
  210. package/scripts/README.md +0 -9
  211. package/scripts/reset-settings.sh +1 -1
  212. package/analysis/ama_fitting/package.json +0 -12
  213. package/analysis/analyze_derivatives.ts +0 -320
  214. package/analysis/derivative_chart_generator.ts +0 -874
  215. package/analysis/trend_detection/SIGNAL_DOCUMENTATION.md +0 -403
  216. package/analysis/trend_detection/derivative_analyzer.ts +0 -1059
  217. package/dist/analysis/analyze_derivatives.d.ts +0 -68
  218. package/dist/analysis/analyze_derivatives.d.ts.map +0 -1
  219. package/dist/analysis/analyze_derivatives.js +0 -287
  220. package/dist/analysis/analyze_derivatives.js.map +0 -1
  221. package/dist/analysis/derivative_chart_generator.d.ts +0 -12
  222. package/dist/analysis/derivative_chart_generator.d.ts.map +0 -1
  223. package/dist/analysis/derivative_chart_generator.js +0 -891
  224. package/dist/analysis/derivative_chart_generator.js.map +0 -1
  225. package/dist/analysis/trend_detection/derivative_analyzer.d.ts +0 -248
  226. package/dist/analysis/trend_detection/derivative_analyzer.d.ts.map +0 -1
  227. package/dist/analysis/trend_detection/derivative_analyzer.js +0 -910
  228. package/dist/analysis/trend_detection/derivative_analyzer.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,78 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [1.6.7] - 2026-09-26 - Native Session Recovery, Start Onboarding, Keys UX, Guard Pivot Persistence
6
+
7
+ ### 2026-09-26
8
+
9
+ - **Fix(concurrency)**: bound the price-correction drain and keep timer lock-waiters out of long broadcast regions — `correctAllPriceMismatches` held `_gridLock` (no acquisition timeout) across every queued correction, running price updates sequentially with `SYNC_DELAY_MS` between each, so a large `ordersNeedingPriceCorrection` backlog could hold the lock for minutes while every concurrent actor died at the 20s fill-lock timeout. Cancel-class entries (duplicate orphans / surplus / type mismatch) are still fully drained — batched, zero-delay, fund-safety-critical — but the sequential update loop is now capped at `FILL_PROCESSING.CORRECTION_MAX_UPDATES_PER_CYCLE` (default 5); the unselected remainder stays queued durably and re-drains next cycle, keeping its queue position so newer entries cannot be starved. A rate-limited backlog alarm (`CORRECTION_QUEUE_WARN_THRESHOLD` default 10, `CORRECTION_QUEUE_WARN_RATE_LIMIT_MS` 5 min) fires even while the drain defers, which is exactly when the queue is growing. The drain also defers *before* acquiring `_gridLock` when `isBroadcastingActive()`, and the maintenance timer loops (open-orders sync, periodic blockchain fetch) get the same pre-acquire deferral via `shouldDeferMaintenanceForBroadcast`; that helper is age-bounded by `BROADCAST_STALE_CLEAR_MS` so a leaked broadcast flag still lets the periodic tick through to run `_clearStaleBroadcastFlag` (deferring on a stale flag would otherwise remove the only watchdog that clears it). `TIMING.FILL_BROADCAST_DEFER_MAX_MS` is now derived as `max(configured, BROADCAST_STALE_CLEAR_MS + 30s)` so a legitimately long startup reconcile Phase 2 cannot outlast the fill-consumer deferral and drop it into the in-lock wait, and the deferral bound re-arms whenever `manager._broadcastingStartedAt` advances (a live region) while a frozen flag still trips the fallback. Startup create-group execution yields to the event loop between groups (`setTimeout(0)`, browser-safe) so the region's timers/watchdogs (region-end reschedule, `_awaitBroadcastIdle`, stale-flag clear) are not starved. Behavioral impact: a correction backlog no longer monopolizes `_gridLock`; fills/corrections still drain, bounded per cycle; the broadcast-deferral bound now outlasts the stale-flag watchdog it depends on; a leaked broadcast flag still self-heals. Risk: only the sequential price-update loop is budgeted, so a very large update backlog drains over multiple cycles (`modules/order/utils/order.ts`, `modules/constants.ts`, `modules/dexbot_fill_runtime.ts`, `modules/dexbot_maintenance_runtime.ts`, `modules/order/grid_reconcile_internal.ts`, `modules/order/manager.ts`, `tests/test_correction_queue_staleness.ts`, `tests/test_fill_pipeline_robustness.ts`, `tests/test_lock_bypass_guards.ts`).
10
+
11
+ - **Fix(logging)**: restore PM2 log output — the `Logger` stacked two independent suppressions: it auto-quieted console output whenever PM2 log paths were present (`quietUnderPm2` defaulted true) **and** skipped its own file writes under PM2, so every line from a PM2-managed bot, the credential daemon, and the module loggers was dropped (the content in `profiles/logs/*.log` came from non-PM2 runs; PM2's own `out_file`s stayed empty). The constructor no longer auto-quiets: under PM2 stdout is the only sink and PM2's `log_date_format` supplies the timestamp, while non-PM2 runs with a `logFile` stay console-quiet to avoid duplicate output. `quietUnderPm2: true` remains as an explicit opt-in to the legacy silent behaviour, and new `isPm2LogCaptureActive()` centralizes the `pm_out_log_path`/`pm_err_log_path` predicate shared by the constructor and `_enqueueWrite` (`modules/order/logger.ts`, `tests/test_logger.ts`).
12
+
13
+ - **Fix(pm2)**: enable real log rotation — PM2 core ignores the per-app `max_size` option, so PM2-owned log files were never rotated. The launcher now installs and configures `pm2-logrotate` (100M per file, retain 10, compressed) on first start; detection via `pm2 jlist` keeps it idempotent and the step is best-effort with timeouts so startup never blocks on a failed install. New `runPm2Raw()` covers the module-management verbs (`jlist`/`install`/`set`) that fall outside `execPM2Command`'s process-control whitelist (`pm2.ts`, `docs/LOGGING.md`).
14
+
15
+ - **Feat(guard)**: persist/restore the LAST-FILL-GUARD pivot with the grid snapshot — the guard was fully disabled after every restart (in-memory `_lastFilledPrice`/`_lastFilledType` reset to null) precisely while the boundary was still being rebuilt, and the book seed (`seedLastFilledPricesFromBook`) that re-armed it is only a proxy (max resting buy / min resting sell) that goes wrong whenever the book isn't adjacent to the last fill (partials, rotations, reserve shelf, dust). `persistGridSnapshot` now builds a `{price, type, fillsAt, genesisHash}` row (`buildLastFillPivotPayload`) and passes it as `storeMasterGrid`'s 10th param; `grid.loadGrid` restores it via `restoreLastFillPivot` right after `_restoreBoundary` — with genesis applied and the grid re-typed, before the first reconcile/broadcast — so startup, price-match resume, and the recovery reload all inherit it from one call site. The row carries the CURRENT live genesis hash, so a regenerated/re-derived grid refuses a pivot from a dead generation. Restore validation runs TTL → genesis binding → on-grid: the TTL is 24h (`GRID_LIMITS.LAST_FILL_PIVOT_TTL_MS`) with the ORIGINAL `fillsAt` preserved through `setLastFillPivot`'s `atMs`, so it keeps meaning "age of the last fill", not "time since last restart"; the on-grid check reuses the runtime's own `resolveOnGridPivot` ladder validator (lazily required from `utils/system.ts` so one increment fallback chain and one drift rule serve both the per-probe live guard and the restore; the snapped ladder level is restored, never the raw float; an off-ladder row falls back to the book seed). TTL and genesis-mismatch verdicts erase the stored row through one shared drop path (`AccountOrders.clearPersistedLastFillPivot`, so no half-invalid row can re-arm the same verdict next boot). The fill-ledger reconstruction alternative was rejected: a snapshot mirror invalidates in lockstep with the boundary instead of maintaining a second source of truth (`modules/account_orders.ts`, `modules/order/utils/system.ts`, `modules/order/grid.ts`, `modules/constants.ts`).
16
+
17
+ - **Refactor(guard)**: centralize LAST-FILL-GUARD pivot mutation behind one provenance-tagged writer — fills persist, heuristics don't. New shared `setLastFillPivot(type, price, 'fill'|'book', atMs?)` in `utils/system.ts` sets `_lastFilledPrice`/`_lastFilledType`/`_lastFilledAt`, a `lastFillPivotSource` flag, and the per-side `_lastFilledBuyPrice`/`_lastFilledSellPrice` mirror in one place; `OrderManager._setLastFillPivot` delegates to it and cow_runtime's queued-fill refresh calls it directly, replacing three hand-rolled scalar-mutation sites. Only `'fill'` provenance is persist-eligible, so a book seed never fossilizes as market truth. The row shape is validated by one shared gate (`normalizeLastFillPivot`) used by both the `storeMasterGrid` sanitizer and the loader, so the two checks cannot drift (`modules/order/manager.ts`, `modules/dexbot_cow_runtime.ts`, `modules/order/utils/system.ts`, `modules/account_orders.ts`).
18
+
19
+ - **Fix(guard)**: invalidate the pivot with the grid generation so a rebuilt grid cannot inherit a pivot validated against wiped geometry — `initializeGrid` and `rejectCorruptedGridSnapshot` reset the in-memory pivot via `resetLastFillPivot` (exposed as `OrderManager._resetLastFillPivot`), which clears the FULL scalar family including the per-side mirrors so `seedLastFilledPricesFromBook`'s cold gate is not silently suppressed by stale mirrors after a rebuild; `AccountOrders.clearGrid` wipes the persisted row with the snapshot (`modules/order/grid.ts`, `modules/dexbot_state_recovery.ts`, `modules/order/utils/system.ts`, `modules/account_orders.ts`).
20
+
21
+ - **Test(guard)**: add `tests/test_last_fill_pivot_persistence.ts` (LFP-1..8) covering the store/load round-trip shape gates, null-clears vs undefined-no-op, the provenance gate, the restore validation chain (`fillsAt` preservation, TTL, genesis-mismatch erase, off-ladder refusal), and full-family reset; `test_stale_guard_pivot_fixes` and `test_dexbot_maintenance_runtime_dynamic_weights` updated for the shared writer (`tests/test_last_fill_pivot_persistence.ts`, `tests/test_stale_guard_pivot_fixes.ts`, `tests/test_dexbot_maintenance_runtime_dynamic_weights.ts`).
22
+
23
+ ### 2026-09-25
24
+
25
+ - **Fix(native)**: harden fill-channel watchdog recovery and accounting — follow-up to dead-but-open session recovery: the mechanisms were sound but had gaps that could still leave a wedged fill channel silently unchecked or attribute node health to the wrong cause. `subscriptions` keeps escalating while the channel stays dead (drops the `_channelDegraded` latch — the shared per-client cooldown is the only rate bound) and routes the fast retry-ladder scan through the same re-entrancy guards (`_processingHistory`/reconnecting/pendingScans) as every other scan so it cannot race a poll/notice/resubscribe scan; `chain_client` extracts one `createForcedReconnectGate` per client returning `issued|coalesced|unavailable`, so a coalesced request (another escalation already spent the cooldown) still counts as a recovery cycle — the operator alert and node strike are not starved by the stale-api path — while `unavailable` (no live socket) neither counts nor burns the cooldown; the retry ladder refills only on a genuinely new `issued` teardown and the recovered "after N" clause emits only when N > 0; `warnSubscription` uses per-category throttle keys so callback errors and channel errors cannot mask each other's suppressed counts; the superseded `CHANNEL_RECONNECT_COOLDOWN_MS` is dropped. Behavioral impact: a wedged channel keeps requesting recovery instead of disarming after one attempt, and the unrecoverable-channel alert and fill-channel-unrecoverable node strike fire even when the stale-api escalation holds the cooldown — no forced reconnect alone costs a node a persistent strike (`modules/bitshares-native/chain_client.ts`, `modules/bitshares-native/subscriptions.ts`, `modules/bitshares-native/transport.ts`, `modules/bitshares_client.ts`, `modules/constants.ts`, `docs/LOGGING.md`).
26
+
27
+ - **Fix(native)**: recover dead-but-open sessions and stop stale COW re-broadcasts — two independent stale-bot failure modes a restart alone did not resolve. (1) A server-side login-session swap left cached api ids rejected with `Assert Exception: _local_apis.size() > api_id` while the socket still read "connected", so the normal close/keep-alive recovery never fired, the fill-history scan and its polling loop died, and fills went undetected for hours (the error log took ~95k identical lines). (2) A COW batch validated its plan before the single-flight broadcast wait, so if the slot-holding batch committed a master-grid advance during that wait the deferred batch still shipped its now-stale plan, placing duplicate on-chain orders that had to be cancelled. New `transport.forceReconnect()` reports the active node failed, detaches the old close handler, tears the socket down synchronously (an unresponsive peer may never send its close frame) and reconnects with `wasReconnect` set so the node-failure ledger prefers a different node; both chain clients window stale-id errors (3 within 60s → `forceReconnect`, a single reconnect-race stale id still recovers in place); the fill-channel watchdog trips a cooldown-debounced forced reconnect after 3 consecutive history-scan failures with per-account throttled logs ("+N suppressed") while excluding callback/processing errors so a downstream bug cannot reconnect-storm; COW re-validates the plan after winning the broadcast slot and re-plans from the fresh master if it went stale during the wait (only when it was fresh before the wait, so an already-stale plan cannot double the structural-resync request) (`modules/bitshares-native/transport.ts`, `modules/bitshares-native/chain_client.ts`, `modules/bitshares-native/subscriptions.ts`, `modules/constants.ts`, `modules/dexbot_cow_runtime.ts`, `docs/LOGGING.md`).
28
+
29
+ - **Fix(update)**: regenerate ecosystem config in a clean process — the updater imports `dist/modules/paths.js` at startup and Node's ESM registry is keyed by resolved URL for the process lifetime, so `npm run build` rewrites `dist/` on disk but the pre-pull modules stay cached; importing the freshly built `dist/pm2.js` in-process then linked against the stale cached `paths.js` and failed with "does not provide an export named 'printRelocationNotices'" even though the bundle freshness check passed, and the warning handler swallowed it so `profiles/ecosystem.config.cjs` was never regenerated (the same latent bug would have broken the PM2-managed restart path). Both post-build consumers of `dist/pm2.js` — `generateEcosystemConfig()` and `needsMarketAdapter()` — now run in a child process with an empty module registry (new `resolvePm2ModuleUrl()`/`pm2NeedsMarketAdapter()`), and the build script prints a "tsc is compiling ..." notice so the silent window while tsc runs is explained (`scripts/update.ts`, `package.json`).
30
+
31
+ - **Fix(native)**: self-heal stale api_id in the native chain client — the client cached `_dbApiId`/`_historyApiId`/`_broadcastApiId` across websocket reconnects, so a reconnect that swapped the server-side login session without the client observing a `closed` status event left those ids pointing past the new session's `_local_apis` map and every call returned `Assert Exception: _local_apis.size() > api_id`, wedging the fill-history channel (including the periodic fill poll) until a process restart. `login()` (run by `validateNode` on every (re)connect) now resets the cached ids, and `db`/`history`/`network_broadcast` route through `callWithApiRecovery()`, which re-registers the namespace on the current session and retries once when the node reports a stale api id — mirrored in `createReadOnlyClient` so the market adapter's read channel is covered too; `processObjects` failures raised by the fill poll are tagged `context: 'fill-poll'` so a dead poll is visible instead of swallowed as a generic error. Risk: one extra RPC round-trip only on a stale-id failure (bounded single retry); no happy-path change (`modules/bitshares-native/chain_client.ts`, `modules/bitshares-native/subscriptions.ts`, `tests/test_native_chain_client.ts`).
32
+
33
+ - **Feat(keys)**: show a BitShares onboarding link for empty vaults and make key/bot tables display-width-aware — a local-document-first onboarding link is printed after first-time vault setup or when authenticating into an empty key manager, with the hosted fallback derived from `UPDATER.REPOSITORY_URL`/`BRANCH` in `modules/constants.ts` instead of a second hardcoded repository URL; stored accounts (`modules/chain_keys.ts`) and configured bots (`modules/account_bots.ts`) render as display-width-aware columns so CJK/emoji and combining marks no longer misalign tables (new browser-safe `modules/utils/text_width.ts`). New `resolveOnboardingUrl()` exported and covered for local/remote selection plus the first-time and empty-vault notice paths (`modules/utils/text_width.ts`, `modules/chain_keys.ts`, `modules/account_bots.ts`, `README.md`, `tests/test_chain_keys_vault.ts`, `tests/test_text_width.ts`).
34
+
35
+ - **Fix(keys)**: signal key-manager cancellation explicitly — the interactive key manager conflated Escape with other exit paths: `authenticate()` returned the raw `'\x1b'` sentinel, which leaked into callers (`key_store`, `chain_orders`, `credential_daemon`, `dexbot_class`, `dexbot`) and was passed to decrypt/resolvePrivateKey as if it were a vault secret, and `main()` returned no status so the first-run flow always claimed the master password was configured even when setup was cancelled. New `MasterPasswordCancelledError` thrown on Escape; `isMasterPasswordFailure()` now recognizes cancellation so existing abort paths handle it; `main()` returns whether a usable vault exists, routes every close through one message, keeps submenu Escape local to the operation, and `selectKeyName()` returns null on cancel; `dexbot.ts` surfaces a cancellation message during first-run setup and honors `main()`'s return value in `runAccountManager` (`dexbot.ts`, `modules/chain_keys.ts`).
36
+
37
+ - **Feat(cli)**: route `dexbot start` through setup onboarding when configuration is incomplete — a bare `dexbot start` (and its `unlock` alias) on a fresh install previously failed downstream with confusing errors because neither a key vault nor bot definitions existed, forcing new users to discover `dexbot key`/`dexbot bot` on their own. Onboarding now runs at the unlock-launcher boundary (`unlock.ts`, shared by `dexbot start`, `dexbot unlock`, and direct `node unlock`, so the dexbot CLI only delegates) with the routing logic in a pure, unit-testable selector (`modules/cli_start_onboarding.ts`); `chain_keys.hasKeySetup()` requires a usable account entry (valid v2 encrypted key) so a cancelled key setup counts as incomplete instead of skipping onboarding; non-interactive `--headless`/`--dryrun` launches fail fast with a message instead of blocking on an interactive prompt; onboarding is opt-in via the direct-run bootstrap so programmatic `unlock.main()` callers (tests, embeds) never block on a password/key prompt; relocation notices are printed explicitly by `dexbot` (non-delegating commands), `unlock` (only when onboarding is not needed), and `pm2` (direct runs), with launcher-child `start`/`unlock`/`pm2` commands excluded to keep a single emission; yellow notice formatting is centralized in `modules/cli_start_output.ts`; README getting-started documents the auto-redirect (`dexbot.ts`, `unlock.ts`, `pm2.ts`, `modules/chain_keys.ts`, `modules/cli_start_onboarding.ts`, `modules/cli_start_output.ts`, `modules/paths.ts`, `README.md`).
38
+
39
+ ## [1.6.6] - 2026-09-25 - Stale Cancellation Guard Hardening, Dead Code Sweep
40
+
41
+ ### 2026-09-25
42
+
43
+ - **Docs**: align the published guides with v1.6.6 behavior — batching, dust handling, spread correction, and the reconciliation safeguards are re-documented to match the current runtime, with stale links and project metadata repaired; `docs/` index targets are added to the npm artifact and the affected file-level API tables and export docs are corrected to describe the actual implementation (`CHANGELOG.md`, `docs/COW_INVARIANTS.md`, `docs/DEXBOT_COMPARISON.md`, `docs/EVOLUTION.md`, `docs/GRID_PRICE_INVARIANT.md`, `docs/GRID_RECONCILE.md`, `docs/architecture.md`, `docs/developer_guide.md`, `modules/README.md`, `package.json`).
44
+
45
+ - **Fix(cleanup)**: remove stale module helpers left behind by browser-portability work, the credit-pricing and COW-runtime extractions, and incomplete determinism plumbing — unused class methods and helper wrappers in accounting, grid, working-grid, export, credit-runtime, and the native crypto browser shim are dropped along with their now-unused imports. Behavioral impact: none — the active accounting, pricing, execution, and shutdown paths are unchanged; the surface is narrower (`modules/bitshares-native/crypto/ecc.browser.ts`, `modules/credit_runtime.ts`, `modules/dexbot_class.ts`, `modules/order/accounting.ts`, `modules/order/export.ts`, `modules/order/grid.ts`, `modules/order/manager.ts`, `modules/order/working_grid.ts`).
46
+
47
+ - **Refactor(analysis)**: drop stale and dead analysis tooling — the grid checker's documentation and output are realigned with LAST-FILL-GUARD semantics, no-op lookup flags are removed from the fill-based tools, zero-consumer module exports are narrowed (`account_resolver`, `fills_source`), and the dependency-free nested AMA-fitting manifests are retired so the analysis surface reflects its actual callers and supported workflows (`analysis/README.md`, `analysis/account_resolver.ts`, `analysis/ama_fitting/package-lock.json`, `analysis/ama_fitting/package.json`, `analysis/bot_usage/kibana_bot_queries.ts`, `analysis/chain_pool.ts`, `analysis/derivative_chart_generator.ts`, `analysis/fills_source.ts`, `analysis/grid_correction_check.ts`, `analysis/resolve_source.ts`, `analysis/trade_profitability.ts`, `scripts/sync-version.ts`).
48
+
49
+ - **Fix(update)**: make the dist freshness check honor the build's `tsconfig.json` exclude — the updater derived expected `dist/` outputs by walking every `.ts` under the compiled roots, so the archived `analysis/legacy/tests` (compiled only by `tsconfig.tests.json`) was read as a missing production output and the post-build check aborted with `Build left dist/ incomplete or stale (is missing dist/analysis/legacy/tests/test_derivative_chart.js)` after a successful build, blocking the restart. `collectCompiledSources` now reads the root `tsconfig.json` `exclude` directory prefixes and skips them, mirroring the compiler; regression in `tests/test_update_dist_freshness.ts` (`scripts/update_dist_freshness.ts`, `tests/test_update_dist_freshness.ts`).
50
+
51
+ - **Refactor(analysis)**: archive the legacy SMA/MACD/RSI derivative analyzer — the classic-indicator tool (superseded by the live Kalman/Hurst/PE stack, with no production importer since `modules/` and `market_adapter/core/` hold none of its symbols) moves to `analysis/legacy/` with a local README. It loses its `analysis:derivatives` npm script, is scrubbed from the centralized docs (`analysis/README.md`, `analysis/trend_detection/README.md`, `scripts/README.md`, `docs/README.md`, `docs/architecture.md`, `docs/developer_guide.md`, `docs/DEXBOT_COMPARISON.md`), and is excluded from the published npm package (`!analysis/legacy` + `!dist/analysis/legacy`). Its four regression tests move under `analysis/legacy/tests/` out of the default `npm test` glob, with a new opt-in `npm run test:legacy`; the production build excludes that path while `tsconfig.tests.json` still typechecks it. Full suite 296/296 pass (`analysis/legacy/`, `package.json`, `tsconfig.json`, `tsconfig.tests.json`, docs).
52
+
53
+ - **Refactor(cache)**: drop legacy run-relative candle-cache migration — stable calendar-month shards are now the only supported format: `*.chunk_*` files are ignored (never loaded, never deleted) instead of being absorbed into shards, and the `*.fetch_manifest.json` identity fallback is removed. The LP fetcher's progress output reads `Window N/M` (was `Chunk N/M`) and its match predicate is renamed `isLpShardMatch`. Refresh/retry/tail semantics are unchanged. Behavioral impact: installs holding only legacy chunks re-fetch once on next run, and the stale files remain inert on disk. Full suite 292/292 pass (`market_adapter/inputs/window_cache.ts`, `market_adapter/inputs/fetch_lp_data.ts`, `tests/test_window_cache.ts`, `market_adapter/README.md`).
54
+
55
+ ### 2026-09-24
56
+
57
+ - **Fix(order-engine)**: close stale-cancellation replays across the correction queue, COW orphan maintenance, and startup reconciliation. Drain-time validation now rechecks live ownership and source-specific geometry for cancel-only, type-mismatch, and gap-evacuation decisions; COW auto-cancel skips adopted orders; startup Phase 2 validates each plan against its own unchanged chain order and live slot/geometry instead of requiring whole-book snapshot equality. Surplus settlement uses only the current live owner and skips stale snapshot fallback. Centralized live-owner lookup across the guards and added regression coverage for truncated/failed pre-cancel reads, per-plan snapshot independence, and stale settlement (`modules/order/utils/order.ts`, `modules/order/grid_reconcile.ts`, `modules/order/grid_reconcile_internal.ts`, `modules/dexbot_cow_runtime.ts`, `tests/test_correction_queue_staleness.ts`, `tests/test_grid_reconcile_regressions.ts`, `tests/test_uncertain_broadcast.ts`).
58
+
59
+ ### 2026-09-23
60
+
61
+ - **Refactor(bot-editor)**: unify the configurator menu labels — abbreviated aliases give way to full names so the same term reads identically in the editor and the docs: `HealthChk` → `Health Check`, `PrefNode` → `Preferred Node`, `Incr` → `Increment`, and `Log lvl` → `Log Level`. The run-together `GridPrice`, `MarketOrder`, and `EdgeOrder` labels keep their casing. Display-only — stored keys, defaults, and validation are unchanged; the `README.md` configurator reference aliases and the `4) Log Level` heading are updated to match (`modules/account_bots.ts`, `README.md`).
62
+
63
+ - **Feat(bot-editor)**: render `5) List bots` as a `Name / Account / Pair` table — the flat `N: name A / B` line gains a bold header and columns derived from the longest value in each field, with palette colors (grey index, green name, orange account, cyan pair) replacing the unlabeled white text, and the pair now reads `A/B` with no spaces around the slash. The `[inactive]`/`(dryRun)` suffixes are colored red/yellow so they stand out. Readability only (`modules/account_bots.ts`).
64
+
65
+ - **Refactor(settings)**: regroup the General Settings menu by concern — `1) Grid Health` → `1) Grid Drift`, `2) Order Recovery` → `2) Order Maint.` (which now also edits the Health Check Interval, moved out of Node Config, so the `Health Check` value reads next to the dust threshold it schedules), and `3) Node Config` narrows to `Nodes` + `Preferred Node`; all five rows are padded to a shared value column. Display/prompt grouping only — stored keys, defaults, and validation are unchanged. Docs: the `README.md` global-settings reference is regrouped to mirror the editor, and `docs/GRID_RECALCULATION.md`'s menu reference now reads `1) Grid Drift` (`modules/account_bots.ts`, `README.md`, `docs/GRID_RECALCULATION.md`).
66
+
67
+ - **Refactor(bot-editor)**: align the per-bot editor with the `bots.json`/runtime vocabulary — the `5) Funding` section is now `5) Inventory` with `Orders` → `MarketOrder` (active window, counted from the market) and `Reserve` → `EdgeOrder` (edge-pinned insurance orders); the `Preferred account` prompts read `Blockchain account`; and `startPrice (pool, book or A/B)` reads `startPrice (pool, book or price)`. `poolRef` is now prompted only when `startPrice` is `pool`: a dormant pin is preserved rather than cleared when switching to `book`/numeric, and the `3) Price` summary renders a dormant pin as grey `ignored` instead of a value that no longer applies. Reserve order counts accept `0`–`100` per side (was `0`–`20`), matching the active-order cap, and the `1)`–`6)` summary rows are column-aligned. Display/validation only — stored keys and defaults are unchanged. New `formatPoolRefLabel` dormant-pin case in `tests/test_account_bots_adapter.ts` (`modules/account_bots.ts`).
68
+
69
+ - **Refactor(cli)**: rebuild `dexbot help` as grouped sections — `printCLIUsage` replaces the hand-padded flat list (which had drifted: duplicate `order` rows, missing `dw`/`export`/`clear-orders`/`clear-market-adapter`/`clear-all`) with five groups (Runtime, Trading, Config, Analysis, Files) plus a Help & options block, deriving the command-column width from the longest entry so alignment cannot drift again. Same commands and aliases; output-only (`dexbot.ts`).
70
+
71
+ - **Docs**: regroup the README configurator reference to mirror the editor — the per-bot parameter tables are split into `1) Pair` … `6) Adapter` and the global-settings tables into `1) Grid Drift` … `5) Updater`, with the previously-undocumented edge-`reserveOrders` semantics and adapter-flag storage (`market_adapter_whitelist.json`, not `bots.json`) called out; the CLI examples gain `export` and the `clear-*` variants. `docs/WORKFLOW.md`'s command table is synced (aliases `keys`/`bots`/`stats`, `dw`, the three `clear-*` commands, `help`), `docs/DEXBOT_COMPARISON.md` now credits the interactive `dexbot bot` editor instead of "manual JSON only", and `market_adapter/README.md` + `scripts/reset-settings.sh` spell the full path `dexbot bot` → `2) Modify bot` → `6) Adapter` (`README.md`, `docs/WORKFLOW.md`, `docs/DEXBOT_COMPARISON.md`, `market_adapter/README.md`, `scripts/reset-settings.sh`).
72
+
73
+ - **Fix(bot-editor)**: accept the pool label's own vocabulary in the `poolRef` prompt — the `3) Price` summary reads green `Pool: default` when the runtime auto-selects the pair's pool, but the pin prompt showed `[none]` and rejected `default`/`pool`/`auto` as invalid, so a user typing what the summary displayed hit an error. `askPoolRef` now treats `default`/`pool`/`auto` as clear aliases (same as `none`/`clear`/`off`/`no`), and when `startPrice` is `pool` the unpinned prompt renders `[default]` instead of `[none]`, matching the summary, and the now-redundant `(none to clear)` hint is dropped from the prompt. New `isPoolStartPrice`/`isPoolRefClearInput` helpers. Display/parsing only — a pin is still either a concrete `1.19.x` ID or absent, and `withPoolRef` is unchanged. Tests: `tests/test_account_bots_adapter.ts` (`modules/account_bots.ts`).
74
+
75
+ - **Fix(grid)**: make `startPrice` the master price source over a pinned `poolRef` — `initializeGrid` passed `manager.config.priceMode || 'auto'`, and `priceMode` is never populated in the bot runtime path, so `startPrice: "book"` was derived as `"auto"` and a pinned `poolRef` won over the order book. New `resolveStartPriceMode()` (`modules/order/utils/withPoolRef.ts`) derives the mode from `startPrice` itself, so `"book"` ignores the pin while `"pool"`/`"auto"` still consult it. Behavioral impact: a bot with `startPrice: "book"` + a pinned pool prices from the order book as documented (previously the pool); numeric startPrice is unchanged. Tests: `tests/test_pool_ref_price.ts` (book mode never fetches the pinned pool; mode resolution) (`modules/order/grid.ts`, `modules/order/utils/withPoolRef.ts`).
76
+
5
77
  ## [1.6.5] - 2026-09-23 - Editor-Managed Whitelist Flags, GridPrice Normalization, Pool/Health Cues, Log-Symmetric Range Tilt, Centralized Bot Defaults, Dynamic-Weight CLI, Update Self-Heal
6
78
 
7
79
  ### 2026-09-23
@@ -20,7 +92,7 @@ All notable changes to this project will be documented in this file.
20
92
 
21
93
  - **Fix(update)**: rebuild when source is current but `dist/` is stale — the git update flow exited before `npm run build` when there were no incoming commits, and tsc's incremental cache will not re-emit an output it believes is current (it will not even recreate a deleted file), so a `dist/` that lagged its source stayed stale while every later run reported "already up to date"; the old guard only checked the `dist/modules/dexbot_class.js` mtime, so a stale `dist/dexbot.js` (holding the CLI alias table) went unnoticed. New `scripts/update_dist_freshness.ts` detects missing/stale outputs without invoking the compiler over exactly the root tsconfig include roots; `scripts/update.ts` self-heals on the no-op path (force a full rebuild, then restart), re-checks and force-emits on the normal path, and `assertDistBundleFresh()` replaces the single-marker guard with a full-bundle check. New `tests/test_update_dist_freshness.ts` covers missing entries, missing/stale counterparts, root-level entry points, and non-compiled files.
22
94
 
23
- - **Feat(defaults)**: centralize bot defaults, settings-doc building, and whitelist flags — seven scattered producers applied `DEFAULT_CONFIG` and whitelist defaults independently and had already drifted. New `modules/bot_defaults.ts` (`seedBotDraft`/`seedBotEntry`/`seedBotRuntimeConfig` with classified key sets, `normalizeBotDraft`/`normalizeBotEntry`) now backs the editor draft, `bot_settings` + claw, and the `OrderManager` constructor. `buildDefaultGeneralSettings()` (`modules/constants.ts`) and `buildNodesView()` (`modules/settings_merge.ts`) give the first-run generator, the editor fallback (`account_bots.loadGeneralSettings`), and the local-overrides merge one shared document (`loadGeneralSettings`/`saveGeneralSettings` now exported). `DEFAULT_WHITELIST_FLAGS`/`AMA_ONLY`/`ALL_ENABLED` constants replace every inline flag literal. Behavioral impact: a draft's `gridPrice` follows a `DEFAULT_CONFIG.gridPrice` override (default stays null here); a missing `bot.active` sources `DEFAULT_CONFIG.active` (was hardcoded true) and claw no longer coerces present null/0, unifying on `active !== false`; `OrderManager` clones absent defaults so config mutations cannot leak into the global default; brand-new first-run settings files gain `NODE_MANAGEMENT`, drop `ANCHOR:{}`, and match the editor key order. Existing `bots.json`/`general.settings.json` are not rewritten (merge output verified byte-identical to a pre-refactor baseline). Tests: 295/295 files passed; new `tests/test_bot_defaults_characterization.ts`, `tests/test_bot_defaults_parity.ts`, and a claw delegation test.
95
+ - **Feat(defaults)**: centralize bot defaults, settings-doc building, and whitelist flags — seven scattered producers applied `DEFAULT_CONFIG` and whitelist defaults independently and had already drifted. New `modules/bot_defaults.ts` (`seedBotDraft`/`seedBotEntry`/`seedBotRuntimeConfig` with classified key sets, `normalizeBotDraft`/`normalizeBotEntry`) now backs the editor draft, `bot_settings` + claw, and the `OrderManager` constructor. `buildDefaultGeneralSettings()` (`modules/constants.ts`) and `buildNodesView()` (`modules/settings_merge.ts`) give the first-run generator, the editor fallback (`account_bots.loadGeneralSettings`), and the local-overrides merge one shared document (`loadGeneralSettings`/`saveGeneralSettings` now exported). `DEFAULT_WHITELIST_FLAGS`/`AMA_ONLY`/`ALL_ENABLED` constants replace every inline flag literal. Behavioral impact: a draft's `gridPrice` follows a `DEFAULT_CONFIG.gridPrice` override (the default was still null at this stage of the refactor; a subsequent change in the same release set it to `ama3`); a missing `bot.active` sources `DEFAULT_CONFIG.active` (was hardcoded true) and claw no longer coerces present null/0, unifying on `active !== false`; `OrderManager` clones absent defaults so config mutations cannot leak into the global default; brand-new first-run settings files gain `NODE_MANAGEMENT`, drop `ANCHOR:{}`, and match the editor key order. Existing `bots.json`/`general.settings.json` are not rewritten (merge output verified byte-identical to a pre-refactor baseline). Tests: 295/295 files passed; new `tests/test_bot_defaults_characterization.ts`, `tests/test_bot_defaults_parity.ts`, and a claw delegation test.
24
96
 
25
97
  - **Feat(bot-editor)**: manage market-adapter whitelist flags from the editor — the per-bot Price/Weight/Range flags (`ama`/`dynamicWeight`/`asymmetricBounds`) previously required running the `dexbot white` script with the correct `botKey`; a wrong key silently wrote a useless entry and the script remained the only way to flip a single flag. New `6) Adapter` section in `modules/account_bots.ts` stages the three flags and commits them only after `bots.json` saved (migrating the entry on rename); `parseBooleanInput` fixes `askBoolean` parsing `'true'` as false and accepting any garbage (`y`/`yes`/`true`, `n`/`no`/`false`, Enter keeps current). `modules/market_adapter_whitelist.ts` gains `setWhitelistFlags()`/`renameWhitelistEntry()` read-modify-write helpers — an occupied key refuses the rename, a malformed file aborts instead of clobbering, legacy array-form entries are preserved, and keys are written sorted. Docs now point to `dexbot bot` -> `6) Adapter`. New `tests/test_account_bots_adapter.ts` (boolean parsing, flag writes, rename/collision, legacy and malformed-file coverage); `npm test` 293 passed / 0 failed, `verify:browser-bundle` 39/39, `tsc --noEmit` clean. Risk: writes touch the same file `dexbot white` owned; unchanged flags are never rewritten.
26
98
 
@@ -763,10 +835,10 @@ All notable changes to this project will be documented in this file.
763
835
  - **Fix**: prevent bot hangs via centralized timeout + node failover — after exhausting 3-attempt retry budget, `withBlockchainRetry` force-blacklists the stuck node and reconnects to a healthy one. All blockchain ops (fetchAccountTotals, readOpenOrders, syncFromOpenOrders, reconcileGridOrders) get automatic failover. Default `_fillProcessingLock` acquisition timeout (20s) prevents indefinite waits. `recalculateGrid` wrapped in 10-minute `Promise.race` ceiling (`modules/order/utils/system.ts`, `modules/order/manager.ts`, `modules/order/grid.ts`).
764
836
  - **Refactor**: centralize `withBlockchainRetry` into shared utility in `system.ts` — replaces local copy in `grid.ts` and inline `Promise.race` in `dexbot_startup_runtime.ts`, giving the startup path retries + node failover too (`modules/order/utils/system.ts`, `modules/order/grid.ts`, `modules/dexbot_startup_runtime.ts`).
765
837
  - **Fix**: prevent duplicate grid-level CREATEs via 4-layer validator guard — `validateCreateTargetSlots` extended with slot occupancy, master grid price collision, chain orphan collision, and same-batch duplicate detection. Also hardens `checkSpreadCondition` against TOCTOU between lock release and broadcast (`modules/order/utils/validate.ts`, `modules/order/grid.ts`, `modules/dexbot_cow_runtime.ts`).
766
- - **Fix**: prevent false-positive excess cancellation on fresh grid — guard `_reconcileStartupSide` cancelCount with `matchedOnGrid > 0` to avoid destroying legitimate orders when no grid slot yet assigned ([GRID_RECONCILE.md](docs/GRID_RECONCILE.md#fresh-grid-guard)). Fix reconcile timeout death spiral by overriding timeout to 300s so Phase 2 batch creates finish in one shot (`modules/order/grid.ts`, `modules/order/grid_reconcile_internal.ts`).
838
+ - **Fix**: prevent false-positive excess cancellation on fresh grid — guard `_reconcileStartupSide` cancelCount with `matchedOnGrid > 0` to avoid destroying legitimate orders when no grid slot yet assigned ([GRID_RECONCILE.md](docs/GRID_RECONCILE.md#fresh-grid-guard-matchedongrid--0)). Fix reconcile timeout death spiral by overriding timeout to 300s so Phase 2 batch creates finish in one shot (`modules/order/grid.ts`, `modules/order/grid_reconcile_internal.ts`).
767
839
  - **Fix**: prevent cross-side spread correction via boundary-correct type filter — hoist boundary computation before both candidate pools and filter `typedSpreadCandidates` by `getSlotCorrectType(o) === railType` to prevent activating a SPREAD slot on the wrong rail after fill-induced boundary shifts (`modules/order/grid.ts`).
768
840
  - **Fix**: remove dead PARTIAL filter in `recalculateGrid` (raw chain `limit_order` objects never have a `state` property) and fix `withBlockchainRetry` logger arg — pass `manager.logger` directly instead of `{ logger: manager.logger }` (`modules/order/grid.ts`).
769
- - **Fix**: cancel stale surplus orders after Phase 2 settles in reconcileGridOrders — new Phase 3 pass re-fetches chain orders and cancels any exceeding per-side target that are not tracked by any grid slot's `orderId` ([GRID_RECONCILE.md](docs/GRID_RECONCILE.md#phase-3--stale-surplus-cleanup)). Catches orphan orders whose ID was lost when the grid reinitialized mid-resync.
841
+ - **Fix**: cancel stale surplus orders after Phase 2 settles in reconcileGridOrders — new Phase 3 pass re-fetches chain orders and cancels any exceeding per-side target that are not tracked by any grid slot's `orderId` ([GRID_RECONCILE.md](docs/GRID_RECONCILE.md#phase-3--fresh-re-read-adoption-stale-surplus-cleanup)). Catches orphan orders whose ID was lost when the grid reinitialized mid-resync.
770
842
  - **Test**: new `testNoExcessCancelWhenMatchedOnGridIsZero` regression test — fresh grid with `matchedOnGrid=0`, non-zero chainCount+targetCount asserts zero cancel calls (`tests/test_grid_reconcile_regressions.ts`).
771
843
  - **Test**: `testPhase3CancelsStaleSurplusUntrackedByGrid` — 7 chain sells, target 5, all-VIRTUAL grid with matchedOnGrid=0, verifies Phase 3 cancels exactly 2 untracked surplus and does NOT cancel any tracked order (`tests/test_grid_reconcile_regressions.ts`).
772
844
  - **Test**: 9 scenarios in `test_validate_create_target_slots.ts` covering all four guard layers, released slots, malformed chain candidates, and no-assets fallback (`tests/test_validate_create_target_slots.ts`).
@@ -1314,7 +1386,7 @@ All notable changes to this project will be documented in this file.
1314
1386
 
1315
1387
  ### 2026-07-01
1316
1388
 
1317
- - **Fix**: prevent stale dust duplicates at the same price level — sync engine rejects orphan adoption when an active order already occupies that price. Reconcile unconditionally cancels duplicate chain orders on chain via `_cancelChainOrder` with `releaseUntrackedFunds: true` ([GRID_RECONCILE.md](docs/GRID_RECONCILE.md#duplicate-tolerance-5%C3%97-multiplier)). Dust detection expanded to interior partials sharing a price level with an active sibling.
1389
+ - **Fix**: prevent stale dust duplicates at the same price level — sync engine rejects orphan adoption when an active order already occupies that price. Reconcile unconditionally cancels duplicate chain orders on chain via `_cancelChainOrder` with `releaseUntrackedFunds: true` ([GRID_RECONCILE.md](docs/GRID_RECONCILE.md#duplicate-cancellation)). Dust detection expanded to interior partials sharing a price level with an active sibling.
1318
1390
  - **Chore**: version bumped to 1.0.5 across all manifests.
1319
1391
  - **Docs**: updated `CHANGELOG.md`, `docs/EVOLUTION.md`, `docs/README.md`, `docs/DEXBOT_COMPARISON.md`, `docs/FUND_MOVEMENT_AND_ACCOUNTING.md`.
1320
1392
 
package/README.md CHANGED
@@ -169,26 +169,30 @@ Keep the default settings first, and tune these:
169
169
  (super-mountain); the default `{ "sell": 1.0, "buy": 1.0 }` suits most
170
170
  setups.
171
171
 
172
- 4. **Set `gridPrice` to `"ama"`** — so the market adapter can center the grid
173
- on AMA. Pick a specific preset if desired: `"ama1"` is the fastest,
174
- `"ama4"` the slowest, and `"ama"` uses the pair's default preset.
172
+ 4. **Enable AMA** — new bots anchor on `gridPrice: "ama3"`, but the market
173
+ adapter only goes live once its per-bot `Price` flag is on. Open
174
+ `dexbot bot` → `2) Modify bot` → pick the bot → `6) Adapter` and set the
175
+ flags:
175
176
 
176
- 5. **Set the adapter flags** — `dexbot bot` → `2) Modify bot` → pick the bot
177
- → `6) Adapter`:
178
-
179
- - `Price` — AMA pricing and live adapter writes (turn **on** for AMA bots;
180
- without it the adapter only dry-runs)
177
+ - `Price` — **on for AMA bots**; without it the adapter only dry-runs
181
178
  - `Weight` — dynamic buy/sell weights (opt-in)
182
179
  - `Range` — AMA-slope range scaling (opt-in)
183
180
 
181
+ To change how closely the grid center tracks the market, set `gridPrice`
182
+ in `3) Price` to `"ama1"`–`"ama4"`: `"ama1"` reacts fastest, `"ama4"`
183
+ slowest and steadiest (higher numbers smooth more), or `"ama"` for the
184
+ pair's default preset.
185
+
184
186
  The flags are stored per bot in `market_adapter_whitelist.json` in the
185
187
  profiles directory and can be changed any time from the same editor
186
188
  section. Boolean prompts accept `y`/`yes`/`true` and `n`/`no`/`false`;
187
189
  Enter keeps the current value.
188
190
 
189
- 6. **Start DEXBot2** with `dexbot start`.
191
+ 5. **Start DEXBot2** with `dexbot start`. If setup is incomplete, `start`
192
+ automatically opens `dexbot key` when no usable account key is configured,
193
+ or `dexbot bot` when a valid key exists but no bot is configured.
190
194
 
191
- 7. **Tune `minPrice` / `maxPrice`** around the market's volatility range. Once
195
+ 6. **Tune `minPrice` / `maxPrice`** around the market's volatility range. Once
192
196
  AMA is active, tighten them around the maximum expected market volatility
193
197
  instead of using an unnecessarily wide range.
194
198
 
@@ -200,39 +204,106 @@ Configuration options from `dexbot bot`, stored in `bots.json` in the profiles d
200
204
 
201
205
  <details><summary><mark>Full parameter reference (click to expand)</mark></summary>
202
206
 
207
+ Grouped exactly as the bot editor shows them (`dexbot bot` → `2) Modify bot` → pick the bot):
208
+
209
+ **`1) Pair`**
210
+
203
211
  | Parameter | Type | Description |
204
212
  | :--- | :--- | :--- |
205
213
  | **`assetA`** | string | Base asset |
206
214
  | **`assetB`** | string | Quote asset |
215
+
216
+ **`2) Identity`**
217
+
218
+ | Parameter | Type | Description |
219
+ | :--- | :--- | :--- |
207
220
  | **`name`** | string | Friendly name for logging and CLI selection |
208
- | **`active`** | boolean | `false` to keep config without running |
209
- | **`dryRun`** | boolean | Simulate orders without broadcasting |
210
221
  | **`preferredAccount`** | string | BitShares account name for trading |
211
- | **`startPrice`** | num \| str | Initial price and adapter source. Default `"pool"` uses the liquidity-pool price; `"book"` uses the live order book mid price (best bid/ask); a number uses a fixed anchor. |
212
- | **`poolRef`** | string \| null | Optional pinned pool ID for `startPrice: "pool"`. Overrides pool discovery with a direct fetch (e.g. `"1.19.48"` or `"48"`). Useful when the trading pair has no native pool. Default `null`. |
213
- | **`minPrice`** | num \| str | Lower bound. Default `"2x"` means `gridPrice / 2` when AMA is active, otherwise `startPrice / 2`. |
214
- | **`maxPrice`** | num \| str | Upper bound. Default `"2x"` means `gridPrice * 2` when AMA is active, otherwise `startPrice * 2`. |
215
- | **`gridPrice`** | num \| str \| null | Grid reference. Use `"ama"` for the recommended AMA center (`"ama"` picks the pair's default preset; `"ama1"`–`"ama4"` pin fastest to slowest); `null` falls back to `startPrice`; numeric values use that fixed value. |
216
- | **`incrementPercent`** | number | Geometric step between orders. Default `0.5` = 0.5%. |
217
- | **`targetSpreadPercent`** | number | Width of the empty spread zone between buy and sell orders. Default `2` = 2%. Profit per completed cycle ≈ `spread - increment - fees`. |
218
- | **`weightDistribution`** | object | Advanced sizing control per side. Range `-1` to `2`: `-1` = super-valley, `0` = valley, `0.5` = neutral, `1` = mountain (default), `2` = super-mountain. Higher weight = more funds in orders near the market price; lower weight = more funds shifted toward the grid edge. Default `{ Sell: 1.0, Buy: 1.0 }`; leave unchanged for normal setup. |
219
- | **`botFunds`** | object | Capital: `{ Sell: "100%", Buy: 100% }`. Numbers or percentage strings |
220
- | **`activeOrders`** | object | Target active orders per side: `{ S: 20, B: 20 }` |
221
- | **`reserveOrders`** | object | Edge-pinned insurance orders resting live outside the active window, to catch fat fingers: `{ S: 0, B: 0 }` |
222
+ | **`active`** | boolean | Default `true`. `false` keeps the config without running it |
223
+ | **`dryRun`** | boolean | Default `false`. Simulate orders without broadcasting |
224
+
225
+ **`3) Price`**
226
+
227
+ | Parameter | Type | Description |
228
+ | :--- | :--- | :--- |
229
+ | **`minPrice`** | num \| str | `Range` lower bound. Default `"2x"` means `gridPrice / 2` when AMA is active, otherwise `startPrice / 2` |
230
+ | **`maxPrice`** | num \| str | `Range` upper bound. Default `"2x"` means `gridPrice * 2` when AMA is active, otherwise `startPrice * 2` |
231
+ | **`startPrice`** | num \| str | `Start` — initial price and adapter source. Default `"pool"` uses the liquidity-pool price; `"book"` uses the live order book mid price (best bid/ask); a number uses a fixed anchor |
232
+ | **`poolRef`** | string \| null | `Pool` — optional pinned pool ID for `startPrice: "pool"`. Overrides pool discovery with a direct fetch (e.g. `"1.19.48"` or `"48"`). Useful when the trading pair has no native pool. Ignored when `startPrice` is `"book"` or a number — `startPrice` is the master source. Default `null`; in the editor, `none`/`clear` (or the aliases `default`/`pool`/`auto`) clears the pin |
233
+ | **`gridPrice`** | num \| str \| null | `GridPrice` — grid reference for the x-factor bounds. Use `"ama"` for the recommended AMA center (`"ama"` picks the pair's default preset; `"ama1"`–`"ama4"` pin fastest to slowest; default `"ama3"`); `null` falls back to `startPrice`; numeric values use that fixed value |
234
+
235
+ **`4) Grid`**
236
+
237
+ | Parameter | Type | Description |
238
+ | :--- | :--- | :--- |
239
+ | **`weightDistribution`** | object | `Weights` — advanced sizing control per side. Range `-1` to `2`: `-1` = super-valley, `0` = valley, `0.5` = neutral, `1` = mountain (default), `2` = super-mountain. Higher weight = more funds in orders near the market price; lower weight = more funds shifted toward the grid edge. Default `{ sell: 1, buy: 1 }`; leave unchanged for normal setup |
240
+ | **`incrementPercent`** | number | `Increment` — geometric step between orders. Default `0.5` = 0.5% |
241
+ | **`targetSpreadPercent`** | number | `Spread` — width of the empty spread zone between buy and sell orders. Default `2` = 2%.<br>Profit per completed cycle ≈ `spread - increment - fees`. Must be at least 2.1 × `incrementPercent` |
242
+
243
+ **`5) Inventory`**
244
+
245
+ | Parameter | Type | Description |
246
+ | :--- | :--- | :--- |
247
+ | **`botFunds`** | object | `Sell`/`Buy` — capital allocation: `{ sell: "100%", buy: "100%" }`. Numbers or percentage strings |
248
+ | **`activeOrders`** | object | `MarketOrder` — target active orders per side, counted closest to the market: `{ sell: 20, buy: 20 }` |
249
+ | **`reserveOrders`** | object | `EdgeOrder` — edge-pinned insurance orders resting live outside the active window, to catch fat fingers: `{ buy: 0, sell: 0 }` (`buy` pins the grid floor, `sell` the grid ceiling; `0` disables per side) |
250
+
251
+ **`6) Adapter`**
252
+
253
+ These three booleans are stored per bot in `market_adapter_whitelist.json`, **not** in `bots.json`:
254
+
255
+ | Flag | Description |
256
+ | :--- | :--- |
257
+ | `ama` (Price) | AMA pricing and live adapter writes. Turn on for AMA bots; without it the adapter only dry-runs |
258
+ | `dynamicWeight` (Weight) | Dynamic buy/sell weights (opt-in; only takes effect while Price is on) |
259
+ | `asymmetricBounds` (Range) | AMA-slope range scaling (opt-in; only takes effect while Price is on) |
222
260
 
223
261
  </details>
224
262
 
225
- ### General Options (Global)
263
+ ### General Settings (Global)
264
+
265
+ General settings via `dexbot bot`, stored in `general.settings.json` in the profiles directory:
226
266
 
227
- Global settings via `dexbot bot`, stored in `general.settings.json` in the profiles directory:
267
+ <details><summary><mark>General settings reference (click to expand)</mark></summary>
228
268
 
229
- <details><summary><mark>Global settings reference (click to expand)</mark></summary>
269
+ Grouped exactly as `dexbot bot` → `6) General settings` shows them:
230
270
 
231
- - **Grid Health**: Grid Funds Regeneration % (default `3%`), RMS Divergence Threshold % (default `14.3%`), AMA Δ Threshold % (default `1%`, AMA center move that triggers a grid reset), AMA-Slope Δ Threshold % (default `8%`, slope-delta trigger as a percentage of max AMA slope)
232
- - **Order Recovery**: Partial Dust Threshold % (default `5%`), Dust Cancel Delay (default `30s`, `-1` = off, `0` = instant)
233
- - **Node Configuration**: Node List (10 default public BitShares nodes), Health Check Interval (default `240 min`), Preferred Node (default `none`)
234
- - **Log Level**: `debug`, `info`, `warn`, `error`, `critical`. Fine-grained category control via `LOGGING_CONFIG` (see [Logging](docs/LOGGING.md))
235
- - **Updater**: Active (default `OFF`), Branch (`auto`/`main`/`dev`/`test`), Interval (default `1 day`), Time (default `00:00`)
271
+ **`1) Grid Drift`**
272
+
273
+ | Setting | Default | Description |
274
+ | :--- | :--- | :--- |
275
+ | Grid Funds Regeneration % | `3` | `Funds` — recalculates grid size when spare funds reach this % of a side's allocation (or the tracked grid overshoots allocation by this %) |
276
+ | RMS Divergence Threshold % | `14.3` | `RMS` — triggers a grid reset when the calculated grid diverges from on-chain state; `0` disables (JSON only) |
277
+ | AMA Δ Threshold % | `1` | `AMA Δ` — % move in the AMA center price that triggers a grid reset |
278
+ | AMA-Slope Δ Threshold % | `8` | `AMA-Slope Δ` — slope-delta trigger as a percentage of max AMA slope |
279
+
280
+ **`2) Order Maint.`**
281
+
282
+ | Setting | Default | Description |
283
+ | :--- | :--- | :--- |
284
+ | Partial Dust Threshold % | `5` | `Dust Threshold` — orders below this % of their ideal size are treated as dust and rotated (cancelled and re-placed at proper size) to keep the grid symmetric |
285
+ | Health Check Interval (min) | `240` | `Health Check` — how often nodes are health-checked (stored as milliseconds) |
286
+
287
+ **`3) Node Config`**
288
+
289
+ | Setting | Default | Description |
290
+ | :--- | :--- | :--- |
291
+ | Node List | 7 public BitShares nodes | `Nodes` — sub-editor: `A` add, `R` remove (at least one must remain), `D` done |
292
+ | Preferred Node | `none` | Pin one node URL; empty = automatic latency-based selection with failover |
293
+
294
+ **`4) Log Level`**
295
+
296
+ | Setting | Default | Description |
297
+ | :--- | :--- | :--- |
298
+ | Log Level | `info` | `debug`, `info`, `warn`, `error`. `critical` is only accepted by editing `general.settings.json` directly. Fine-grained category control via `LOGGING_CONFIG` (see [Logging](docs/LOGGING.md)) |
299
+
300
+ **`5) Updater`**
301
+
302
+ | Setting | Default | Description |
303
+ | :--- | :--- | :--- |
304
+ | Active | `OFF` | Enables the automated updater (editor shows `[ON/OFF]`) |
305
+ | Branch | `auto` | `main`, `dev`, `test`, or `auto` (detected current branch) |
306
+ | Schedule | `1` at `00:00` | Cron schedule (`Interval` days, `Time` HH:mm, 24h) |
236
307
 
237
308
  </details>
238
309
 
@@ -258,24 +329,25 @@ First-run details and common mistakes are covered in the [BitShares Onboarding T
258
329
 
259
330
  ```bash
260
331
  dexbot key # Master password/keyring
261
- dexbot bot # Interactive bot configurator (adapter Price/Weight/Range flags: 6) Adapter)
332
+ dexbot bot # Interactive bot configurator (adapter flags: 2) Modify bot → 6) Adapter)
262
333
 
263
334
  dexbot reset {all|<bot>} # Regenerate grid
264
335
  dexbot disable {all|<bot>} # Disable bot in config
265
336
  dexbot enable {all|<bot>} # Enable bot in config
266
337
 
267
338
  dexbot stat # Runtime status (unlock or PM2)
268
- dexbot order [<bot>] # Analyze order grids
269
- dexbot order --export # Export as HTML to analysis/charts/
339
+ dexbot order [<bot>] # Analyze order grids (--export → HTML to analysis/charts/)
270
340
  dexbot tv <bot|pool|A/B> # TradingView 1h chart with AMA overlay (default: 3 months)
271
341
  dexbot credit [<bot>] # Live summed MPA + borrowed-credit positions per asset per bot
342
+ dexbot export <bot> # Export trades + settings (CSV/JSON) for analysis/
272
343
 
273
344
  dexbot update # Update DEXBot2
274
- dexbot clear # Clear log files
345
+ dexbot clear # Clear log files (also clear-orders, clear-market-adapter, clear-all)
275
346
  dexbot default # Reset settings to defaults
347
+ dexbot help # Grouped command reference
276
348
  ```
277
349
 
278
- ## ⚙️ PM2 Process Management
350
+ ## 🎯 PM2 Process Management
279
351
 
280
352
  PM2 is optional — `dexbot start` is the native solution.
281
353
 
@@ -21,7 +21,7 @@ Tools that inspect DEXBot trading behavior and the market data it operates on. O
21
21
  | Tool | Ask this when… | One-line command |
22
22
  |------|----------------|------------------|
23
23
  | [`trade_profitability.ts`](#trade-profitability-analyzer-trade_profitabilityts) | "Is my bot making money?" — PnL, R-multiples, drawdown | `npm run analysis:trade-pnl -- <account-id>` |
24
- | [`grid_correction_check.ts`](#grid-correction-check-grid_correction_checkts) | "Is my grid placing orders monotonically?" — sell/buy price inversion detector | `npm run analysis:grid-check -- --bot-key <bot-key>` |
24
+ | [`grid_correction_check.ts`](#last-fill-guard-check-grid_correction_checkts) | "Are fills respecting the pivot ± half-increment guard?" | `npm run analysis:grid-check -- --bot-key <bot-key>` |
25
25
  | [`analyze_risk_profile.ts`](#risk-profile-analyzer-analyze_risk_profilets) | "How wide should my Safe Range clamps be?" | `node dist/analysis/analyze_risk_profile.js --bot-key <bot-key>` |
26
26
  | [`analyze_trade_heatmap.ts`](#trade-heatmap-analyze_trade_heatmapts) | "Where did trade volume cluster vs the AMA?" | `node dist/analysis/analyze_trade_heatmap.js --bot-key <bot-key>` |
27
27
  | [`tradingview/analyze_tradingview.ts`](#tradingview-chart-tradingviewanalyze_tradingviewts) | "Just give me a candle chart" | `dexbot tv <bot-key>` |
@@ -32,8 +32,6 @@ Tools that inspect DEXBot trading behavior and the market data it operates on. O
32
32
  | [`ama_fitting/`](#ama-fitting) | "Which AMA preset fits this market?" | `node dist/analysis/ama_fitting/optimizer_high_resolution.js --data <lp-file>` |
33
33
  | [`bot_fitting/`](#bot-fitting) | "What spread / increment / ratio for my grid?" | `node dist/analysis/bot_fitting/backtest_ama_sweep.js --data <lp-file>` |
34
34
 
35
- > `analyze_derivatives.ts` (SMA / MACD / RSI derivative layer, uses `derivative_chart_generator.ts`) is a legacy tool surfaced via `npm run analysis:derivatives` — kept for reference.
36
-
37
35
  > `<account-id>` = a BitShares `1.2.x` account ID or name. `<bot-key>` = a key from `profiles/bots.json`. `<lp-file>` = a JSON file under `market_adapter/data/lp/<pair>/lp_pool_<id>_<interval>.json`.
38
36
 
39
37
  ## Key Terms
@@ -164,7 +162,6 @@ node dist/analysis/trade_profitability.js 1.2.123456 \
164
162
  | `--end <iso>` | — | End time |
165
163
  | `--hours <n>` | `168` (7d) | Lookback hours (alternative to start/end) |
166
164
  | `--asset <id>` | all | Filter to one base asset ID |
167
- | `--lookup` | off | Legacy (no-op): account names always resolve automatically |
168
165
  | `--refresh-account` | off | Force re-resolution and update the stored `accountId` |
169
166
  | `--csv <file>` | — | Export chronologically sorted trade list |
170
167
  | `--json <file>` | — | Export full analysis with per-pair PnL data |
@@ -223,11 +220,11 @@ node dist/analysis/trade_profitability.js 1.2.123456 \
223
220
 
224
221
  </details>
225
222
 
226
- ### Grid Correction Check (`grid_correction_check.ts`)
223
+ ### LAST-FILL-GUARD Check (`grid_correction_check.ts`)
227
224
 
228
- Validates grid discipline from the same Kibana fill pipeline as `trade_profitability.ts`: two consecutive same-direction fills on a pair must be monotonic — sell prices rising, buy prices falling (equal is OK). An inversion means the bot placed an order below its own previous sell (or above its own previous buy), e.g. an orphaned order filling outside grid accounting. Used as the external regression gate for the orphan-fix plans in `docs/ORDER_ENGINE_POST_1.0_RETROSPECTIVE.md`.
225
+ Validates LAST-FILL-GUARD discipline from the same Kibana fill pipeline as `trade_profitability.ts`. For a previous fill at price `x` and grid increment `i`, the next order must satisfy `BUY < x × (1 − i/2/100)` and `SELL > x × (1 + i/2/100)`, regardless of the previous fill's side. A violation is a buy or sell fill inside the prohibited half-increment band around its pivot.
229
226
 
230
- **Pipeline:** Kibana `fill_order` query (paginated `search_after`) → on-chain asset precision resolution → buy/sell classification → chronological sort → per-order/price-epoch aggregation (partial fills at one price collapsed to weighted-average; repriced order lifetimes kept separate) → consecutive same-direction pair comparison → violation report with daily histogram.
227
+ **Pipeline:** Kibana `fill_order` query (paginated `search_after`) → on-chain asset precision resolution → buy/sell classification → chronological sort → per-order/price-epoch aggregation (partial fills at one price collapsed to weighted-average; repriced order lifetimes kept separate) → consecutive pivot-band comparison → violation report with daily histogram.
231
228
 
232
229
  ```bash
233
230
  # Per-order aggregated check (default), last 7 days
@@ -239,8 +236,8 @@ npm run analysis:grid-check -- --bot-key <bot-key> --hours 720 --json out.json -
239
236
  # Raw fill granularity instead of per-order aggregation
240
237
  npm run analysis:grid-check -- --bot-key <bot-key> --per-fill --hours 168
241
238
 
242
- # Forgive small adverse moves within 0.1%
243
- npm run analysis:grid-check -- --bot-key <bot-key> --hours 168 --tolerance 0.1
239
+ # Override the bot's configured grid increment
240
+ npm run analysis:grid-check -- --bot-key <bot-key> --hours 168 --increment 0.5
244
241
  ```
245
242
 
246
243
  Exit code `0` = pass, `2` = violations found, `1` = fatal error. Bot keys resolve via `profiles/bots.json` (`--list-bots` to enumerate); the account defaults to the bot's stored `accountId` when present (no chain lookup — the ID is auto-saved next to `preferredAccount` after the first successful name resolution, re-verified with `--refresh-account`), otherwise `preferredAccount` is resolved on-chain, and can be overridden with `--account <1.2.x|name>`.
@@ -253,18 +250,18 @@ Exit code `0` = pass, `2` = violations found, `1` = fatal error. Bot keys resolv
253
250
  | `--hours <n>` | `168` | Lookback hours from now |
254
251
  | `--start <iso>` / `--end <iso>` | — | Absolute time window |
255
252
  | `--account <id>` | bot `preferredAccount` | Override account ID or name |
256
- | `--lookup` | off | Legacy (no-op): account names always resolve via BitShares node when no stored ID exists |
257
253
  | `--refresh-account` | off | Force re-resolution of `preferredAccount` and update the stored `accountId` when it changed |
254
+ | `--increment <pct>` | bot config / `0.5` | Grid increment used to derive the half-increment guard band |
258
255
  | `--per-fill` | off | Check at fill granularity instead of per-order aggregated |
259
256
  | `--include-cross-pair` | off | Also check consecutive fills across different pairs |
260
- | `--tolerance <pct>` | `0` | Adverse price move (%) forgiven before flagging |
257
+ | `--tolerance <pct>` | — | Deprecated compatibility alias for `--increment`; its value is doubled and a warning is emitted |
261
258
  | `--json <file>` / `--csv <file>` | — | Export violations |
262
- | `--verbose` | off | Print the full trade sequence |
259
+ | `--verbose` | off | Print the fetched trade sequence before checking |
263
260
  | `--list-bots` | — | List available bot keys and exit |
264
261
 
265
262
  </details>
266
263
 
267
- **Notes:** strict sat-level comparison is the ground truth (`--tolerance` only forgives small inversions); partial fills at one price are collapsed to a weighted-average price in the default mode, but fills after a native order repricing are kept in separate price epochs so updated orders are not mixed together.
264
+ **Notes:** this is an offline approximation of decision-time placement. Batch-placed orders can share an earlier pivot, and the tool does not model the runtime spread-correction bypass. In the default mode, partial fills at one price are collapsed to a weighted average while fills from separate native order repricing epochs remain independent.
268
265
 
269
266
  ## Charts & Visualization
270
267
 
@@ -395,7 +392,6 @@ Shared analyzers and chart renderers for the dynamic-weight signal path. Core en
395
392
  **Research docs:**
396
393
  - [README.md](trend_detection/README.md) — directory overview and module index
397
394
  - [DYNAMIC_WEIGHT_RESEARCH.md](trend_detection/DYNAMIC_WEIGHT_RESEARCH.md) — AMA+Kalman blend with Hurst/PE regime gating, formula reference, knob guide
398
- - [SIGNAL_DOCUMENTATION.md](trend_detection/SIGNAL_DOCUMENTATION.md) — legacy SMA/MACD/RSI derivative signal layer
399
395
 
400
396
  <details><summary>Modules (click to expand)</summary>
401
397
 
@@ -509,7 +505,6 @@ These npm scripts wrap common analysis runners:
509
505
  | `npm run analysis:tradingview` | `node dist/analysis/tradingview/analyze_tradingview.js` |
510
506
  | `npm run analysis:trade-pnl` | `node dist/analysis/trade_profitability.js` |
511
507
  | `npm run analysis:grid-check` | `node dist/analysis/grid_correction_check.js` |
512
- | `npm run analysis:derivatives` | `node dist/analysis/analyze_derivatives.js` (legacy SMA/MACD/RSI layer, reference only) |
513
508
  | `npm run ama:chart:lp-local` | `node dist/analysis/ama_fitting/generate_unified_comparison_chart.js` (chart also auto-generated by optimizer) |
514
509
 
515
510
  All accept `--` forwarded flags.
@@ -521,7 +516,7 @@ npm run analysis:tradingview -- --source market_adapter --bot-key <bot-key>
521
516
  # Trade PnL
522
517
  npm run analysis:trade-pnl -- 1.2.123456 --hours 720
523
518
 
524
- # Grid correction check (monotonicity regression gate)
519
+ # LAST-FILL-GUARD check
525
520
  npm run analysis:grid-check -- --bot-key <bot-key> --hours 168
526
521
 
527
522
  # File-based
@@ -158,14 +158,4 @@ async function resolveAccountRef(accountRef: string, options: ResolveOptions = {
158
158
  return { accountId: String(id), botKey: null, botMeta: null, source: 'resolved', reason: null };
159
159
  }
160
160
 
161
- export {
162
- ACCOUNT_ID_RE,
163
- lookupNameOnChain,
164
- resolveBotAccount,
165
- resolveAccountRef,
166
- ResolveOptions,
167
- ResolvedAccount,
168
- ResolveSource,
169
- ResolveFailure,
170
- NameLookup,
171
- };
161
+ export { resolveBotAccount, resolveAccountRef };
@@ -207,5 +207,5 @@ function buildTopUpdaterAccountsQuery(lookbackHours: number, topN: number = 200,
207
207
 
208
208
  // ─── Exports ──────────────────────────────────────────────────────────────────
209
209
 
210
- export { DEFAULT_CONFIG, kibanaSearch, buildOrderPriceQuery, buildTopSellerAccountsQuery, buildTopCancellerAccountsQuery, buildTopFilledAccountsQuery, buildTopUpdaterAccountsQuery, OP_LIMIT_ORDER_UPDATE }
210
+ export { DEFAULT_CONFIG, kibanaSearch, buildOrderPriceQuery, buildTopSellerAccountsQuery, buildTopCancellerAccountsQuery, buildTopFilledAccountsQuery, buildTopUpdaterAccountsQuery }
211
211
 
@@ -44,4 +44,4 @@ async function withReadOnlyClient<T>(fn: (client: any) => Promise<T>): Promise<T
44
44
  }
45
45
  }
46
46
 
47
- export { defaultNodePool, withReadOnlyClient };
47
+ export { withReadOnlyClient };
@@ -219,16 +219,10 @@ async function fetchAllFills(config: any, accountId: string, gte: string, lte: s
219
219
 
220
220
  export {
221
221
  BTS_ID,
222
- OP_FILL_ORDER,
223
- ASSETS,
224
- resolvedPrecisions,
225
222
  assetSymbol,
226
223
  assetPrec,
227
224
  toReal,
228
225
  resolveAssetPrecisions,
229
- buildFillQuery,
230
226
  fetchAllFills,
231
- AssetInfo,
232
- AssetAmount,
233
227
  FillRecord,
234
228
  };