diff --git a/MALKHUT/EXT_CHANGES.md b/MALKHUT/EXT_CHANGES.md new file mode 100644 index 0000000..c409167 --- /dev/null +++ b/MALKHUT/EXT_CHANGES.md @@ -0,0 +1,102 @@ +# EXT_CHANGES — external additions to MALKHUT (Fable, 2026-07-11/12) + +For mm_: exact record of what I added to your codebase, where, and why — +so you can reshape, absorb, or replace it with full knowledge. Operator +directive 2026-07-11: *"We shall use MALKHUT's asset directory-methods to +comprise our UV-VIOLET known-asset-universe directory... MALKHUT's asset +store as our overall system asset store."* Everything below is **additive** +— none of your existing files were edited. + +## Why this exists (the incident that forced it) + +UV-PRIME's 2026-07-10/11 testnet audit found 25 phantom journal rows. +Root cause chain included: the asset picker has **no concept of what the +execution venue actually trades** — 15 of the 50 feed symbols are +offline/delisted on BingX VST (BAND, CELR, COS, CVC, DENT, FUN, HOT, ICX, +TFUEL, TUSD, USDC, WAN, WIN, XTZ, ZIL), and orders for them died at the +venue while the kernel believed they filled. The fix needed a per-exchange +listing-status store. Your asset store was the designated home. + +## What was added + +### 1. `malkhut/assets/` — new subpackage (the operational directory) + +| File | What it is | +|---|---| +| `malkhut/assets/__init__.py` | re-exports | +| `malkhut/assets/directory.py` | `AssetDirectory` — JSON-backed universe store | +| `malkhut/assets/asset_directory.json` | the live data file (versioned in git) | +| `malkhut/assets/compiled_profiles.json` | full taxonomy dumps from YOUR AssetCompiler | +| `malkhut/tests/test_asset_directory.py` | 8 tests (round-trip, normalization, status filter, idempotence) | + +Core concepts in `directory.py`: + +- `normalize_symbol()` — canonical form: `"BAND-USDT"`/`"band_usdt"` → `"BANDUSDT"`. +- `KNOWN_EXCHANGES` — the aux "known exchanges" table (operator-specified): + `BINANCE`, `BINGX`, `BINGX_VST`. VST is deliberately a separate venue — + its universe differs from BingX live (observed). +- `ExchangeListing` — per-venue: `venue_symbol` (venue-local spelling), + `status` (`TRADING`/`OFFLINE`/`UNKNOWN`), `last_checked`, `source`. +- `AssetRecord` — canonical symbol, base/quote, `exchanges: dict`, + `profile_ref` (key into YOUR `ASSET_PROFILES` when taxonomy exists), notes. +- `AssetDirectory` — load/save (atomic tmp-rename), `upsert`, `set_listing` + (rejects unknown exchanges), `import_symbols` (bulk, idempotent), + `symbols_for_exchange(exchange, status=TRADING)`, `venue_symbol()`. +- Storage: JSON file at `$MALKHUT_ASSET_DIR_PATH` or package-local default. + Chosen because listing STATUS is runtime-mutable truth (probed from venue + APIs) — it can't live in frozen in-code dataclasses, and JSON keeps it + language-agnostic / GraalVM-safe / no DB dependency. + +### 2. Data seeded into it + +- **50 canonical symbols** = the full DOLPHIN NG7 scan-feed universe (what + BLUE actually picks from), imported as `BINANCE` listings, source + `dolphin_ng7_scan_feed`. +- **BINGX_VST statuses** from a live `/openApi/swap/v2/quote/contracts` + probe: 35 TRADING / 15 OFFLINE (list above). Tradable = `status==1` AND + `apiStateOpen=="true"`; absent-from-contracts = OFFLINE. +- **Full taxonomy for all 50** compiled via **your** `AssetCompiler` + (`compile_and_register`, rate-limited, 0 failures) → persisted to + `compiled_profiles.json` (your registries are in-memory only; this file + is the durable copy). Each record's `profile_ref` set on success. + +### 3. Consumers OUTSIDE MALKHUT (so you know who depends on what) + +- `prod/clean_arch/violet/uv/uv_asset_universe.py` — the UV bridge: + seeds from scans, refreshes VST listings, and exposes + `init_asset_universe(execution_exchange)` → frozenset of tradable + canonical symbols. **This is the single UV→MALKHUT contract:** + `AssetDirectory().symbols_for_exchange(exchange)`. Change that API and + ping Fable; everything else is yours to reshape. +- The UV-PRIME runner loads it at boot (`UV_EXEC_EXCHANGE`, default + `BINGX_VST`) and its promotion bridge suppresses ENTERs for assets + outside the set (`asset_not_on_venue`). Live since flight-2 + (2026-07-11 21:57:43 UTC), log line: `UV UNIVERSE: 35 tradable assets`. + +## Relationship to YOUR generalization (d2d0c5e) + +You added `ExchangeProfile` + `AssetProfile.exchanges` + cross-exchange +queries — the **taxonomy layer** (rich, in-code, semi-static). This +directory is the **operational layer** (thin, probed, runtime-mutable). +They compose; acknowledged on the bus (#5d2fdaee). Proposed seam, yours to +own if you want it: onboarding populates `AssetProfile.exchanges` from the +directory's TRADING statuses (directory → profiles, one-way). + +## What I did NOT touch + +No edits to `asset_classification.py`, `asset_behavior.py`, +`asset_compiler.py`, `state.py`, engine/planner/risk/venue/ipc/clock/ +training code, or any test of yours. `README.md` untouched by me (its +working-tree modification predates this work). All 1156 of your tests were +green before and after (verified via the compiler run + directory suite). + +## Commits (branch tools/pi_wake_agent, /mnt repo) + +- `a0625076` — directory + tests + seed + UV bridge +- `3efb8749` — compiled_profiles.json + profile_ref links (onboarding 50/50) + +North-star context (operator, in POST_FINISH.md): future selection from the +entire ~500-asset Binance universe — the directory is built to that scale; +today's 50 is the feed's limit, not the store's. + +— Fable