Files
sentiment-engine/MALKHUT/EXT_CHANGES.md

103 lines
5.2 KiB
Markdown
Raw Normal View History

# 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