VIOLET OA: partial spec PASS 7 — V5 selection + multi-asset slots + capital allocation

VIOLET_PART_SPEC_OA_TODO_PASS7.md — the V5 ladder layer as six independent units extending
contracts_v3 (AssetRank/SlotState/CapitalAllocation/SlotPolicy):
  31. Selection contracts + SlotPolicy.
  32. ARS ranking pipeline (faithful to AlphaAssetSelector.rank_assets + OB Sub-1 ±5/10% + IRP
      alignment filter + stablecoin exclusion).
  33. Multi-asset slot manager (max_slots, assignment by rank, hysteresis anti-churn, no double-occ).
  34. Capital allocation across slots (BLUE notional = base_fraction × conviction × capital; no
      invented normalization).
  35. Selection→slot→intent multi-asset DARK flow harness.
  36. Ranking bit-identity @gate vs the real AlphaAssetSelector.

NOTE (CRITICAL #1): the disappointing live parity (pick-match 1.5%, no-pick 86%, sizing near-
identical when aligned) implicates THIS selection/timing layer. PASS 7 PINS the ranking math
bit-for-bit (Task 36), which narrows the live-parity suspect to timing/join — but the
live-aggregate root-cause stays Claude's job (not this pass). Faithful to AlphaAssetSelector /
BIBLE §5; cite kernel file:line. New-file-only under selection/.

Standing ready for PASS 8–9. Added PASS 7 to the review queue in VIOLET_TODO_CRITICAL.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Codex
2026-06-17 10:53:12 +02:00
parent 5f636ef723
commit 0ab83c528a
2 changed files with 181 additions and 0 deletions

View File

@@ -0,0 +1,175 @@
# VIOLET — partial spec for another agent, PASS 7 (OA TODO): V5 SELECTION + MULTI-ASSET SLOTS + CAPITAL ALLOCATION
Date: 2026-06-17. Continues PASS 16 (same V0→V6 plan). PASS 7 is the **V5** layer of the ladder:
faithful IRP/ARS asset RANKING, MULTI-ASSET SLOT management (concurrent positions), and CAPITAL
ALLOCATION across slots. Everything DARK and as independent, separately-testable units sharing the
`contracts_v3` vocabulary.
**⚠️ Relevance to CRITICAL #1 (read `VIOLET_TODO_CRITICAL.md`).** The disappointing live parity
(pick-match 1.5%, no-pick 86%, **but sizing near-identical when assets align**) points squarely at
SELECTION/TIMING, i.e. THIS layer. PASS 7 BUILDS the faithful selection machinery and pins the
ranking bit-for-bit to BLUE's `AlphaAssetSelector` (Task 36). That is COMPLEMENTARY to — not a
substitute for — the live-aggregate parity root-cause, which remains **Claude's** job (the live
join/alignment in `parity_report.py` is the other suspect). Do NOT attempt the live root-cause
here; build the units + the unit-level bit-identity pin.
**Read first (authoritative references — READ ONLY):**
- `nautilus_dolphin/nautilus_dolphin/nautilus/alpha_asset_selector.py``AlphaAssetSelector.rank_assets`
(IRP selection, ARS scoring, BIBLE §5) — the ranking authority.
- `prod/docs/SYSTEM_BIBLE.md` §5 (selection), §490 "OB Sub-1: ARS adjusted ±5%/10% by per-asset OB
depth quality before sorting", §735 OB sub-systems. (BIBLE is directionally right but can be
outdated — verify against the kernel code.)
- `prod/clean_arch/violet/alpha_wrappers.py` (`VioletAssetSelector`, the single-pick wrapper) +
`decision_engine.py` (how a pick + `ars_score` flow today) + `sizing.py` (notional model) — READ,
do NOT edit (in-flight).
- ENGINE_KWARGS selection knobs (`nautilus_event_trader.py:127+`): `use_asset_selection=True`,
`min_irp_alignment=0.0` ("gold spec: no IRP filter"), `max_slots` (launcher venue config).
- Stablecoin exclusion: `decision_engine.STABLECOIN_SYMBOLS` (must match BLUE's set).
---
## 0. HARD RULES (identical to PASS 16 — summarized)
- **Never edit shared files** (`prod/nautilus_event_trader.py`, `clean_arch/dita_v2/**`,
`dita/decision.py`, `nautilus_dolphin/**`, `blue_parity.py`, `prod/bingx/leverage.py`). READ only.
- **VIOLET DARK** — selection/slots/allocation are pure logic over scan + factor inputs; no orders,
no venue, no service/HZ control.
- **V-TYPES on all new code**; faithful poison-guards only; NO arbitrary caps.
- **NEW-FILE-ONLY** under `prod/clean_arch/violet/selection/` (+ extend `contracts_v3.py`). Do NOT
modify in-flight files (`alpha_wrappers.py`, `decision_engine.py`, `sizing.py`,
`live_blue_source.py`, the PASS-5/6 exec files, `cadence.py`, `clock.py`). READ + IMPORT them.
## 0a. COMMIT / BRANCH POLICY (3 shared-index collisions on 2026-06-16 — non-negotiable)
Own `git worktree` (`git worktree add ../vp-oa7 -b agent/oa-violet7`) strongly preferred. Else
never `git add -A`; `git commit -F msg -- <files>` with explicit pathspec; verify
`git show --stat --format="" HEAD` lists ONLY your files. One commit/task, prefix `VIOLET OA:`,
Co-Authored-By trailer. Tests on `/home/dolphin/siloqy_env/bin/python3`. `git grep` only.
---
## I. SHARED INTERFACE EXTENSIONS (add to `contracts_v3.py`; never fork a parallel type)
Reuse PASS-3..6 types. ADD the selection/slot vocabulary (all `StrictModel` / `Annotated`):
1. **`AssetRank`** — `asset: Symbol`, `ars_score: float (finite)`,
`ob_adjusted_score: float (finite)`, `irp_alignment: float`, `irp_passed: bool`, `rank: int (ge=0)`,
`excluded_reason: str = ""` (e.g. "STABLECOIN"/"IRP_FILTER"/"" ).
2. **`SlotState`** — `slot_id: int (ge=0)`, `asset: Optional[Symbol]`, `status: str`
("FREE"/"HELD"/"PENDING"), `held_since_ns: Optional[MonoNs]`.
3. **`CapitalAllocation`** — `slot_id: int`, `asset: Symbol`, `allocated_capital: float (ge=0)`,
`notional_fraction: float (ge=0)`, `conviction_leverage: float (ge=0)`.
4. **`SlotPolicy`** — `max_slots: Annotated[int, Field(ge=1)]`,
`hysteresis_bars: Annotated[int, Field(ge=0)]` (anti-churn), `allow_reentry: bool`.
If a task needs another field, ADD it here and note it.
---
## TASK 31 — Selection contracts + SlotPolicy
**Why.** The shared selection/slot vocabulary everything else imports.
**Affected files (NEW):** extend `contracts_v3.py` (the §I types);
`prod/clean_arch/violet/selection/__init__.py`;
`prod/clean_arch/violet/selection/test_violet_selection_contracts.py`.
**Pass criteria.** All types construct + poison-reject (non-finite scores, negative capital,
max_slots ≥ 1); `excluded_reason` enumerated values documented. No edits outside the new/extended files.
## TASK 32 — ARS ranking pipeline (faithful to AlphaAssetSelector + OB Sub-1 + IRP filter)
**Why.** The heart of selection: reproduce BLUE's full ranking — ARS score → OB Sub-1 adjustment →
IRP alignment filter → stablecoin exclusion → sort. The single-pick `VioletAssetSelector` covers
part of this; PASS 7 builds the FULL multi-asset ranking on top WITHOUT editing it.
**Affected files (NEW):** `prod/clean_arch/violet/selection/rank_pipeline.py`,
`prod/clean_arch/violet/selection/test_violet_rank_pipeline.py`.
**Interface/approach.** `rank_assets(market_data: dict[Symbol, list[float]], *, regime_direction:
int, ob_market=None, min_irp_alignment: float, stablecoins: frozenset[str]) -> list[AssetRank]`:
- Compute the base ARS exactly as `AlphaAssetSelector` (WRAP/transcribe — cite file:line).
- **OB Sub-1** (BIBLE §490): adjust ARS ±5%/10% by per-asset OB depth quality BEFORE sorting (read
the kernel for the exact factors/percentages; if `ob_market` is None, skip the adjustment, as the
no-OB path does).
- **IRP alignment filter:** drop assets with alignment < `min_irp_alignment` (default 0.0 = no
filter, per gold spec) → mark `irp_passed`/`excluded_reason`.
- **Stablecoin exclusion:** any asset in `stablecoins` → excluded (must equal
`decision_engine.STABLECOIN_SYMBOLS`; assert in test).
- Sort descending by `ob_adjusted_score`; assign `rank`. Pure function, deterministic, V-TYPES out.
**Pass criteria.** On crafted market data the ranked order + ARS/ob_adjusted scores match a direct
`AlphaAssetSelector` computation; stablecoins always excluded; IRP filter respected; OB-off path
equals base ARS. No edits outside the 2 files.
## TASK 33 — Multi-asset slot manager (max_slots, assignment, hysteresis)
**Why.** BLUE/VIOLET hold up to `max_slots` concurrent positions; the slot manager decides which
ranked assets occupy slots, with no double-occupancy and anti-churn hysteresis.
**Affected files (NEW):** `prod/clean_arch/violet/selection/slot_manager.py`,
`prod/clean_arch/violet/selection/test_violet_slot_manager.py`.
**Interface/approach.** `SlotManager(policy: SlotPolicy)` holding `list[SlotState]`. `assign(ranked:
list[AssetRank], held: dict[Symbol, OpenPositionView], now_ns) -> list[SlotState]`: keep currently
HELD assets in their slots; fill FREE slots from the top of `ranked` (excluding already-held and
excluded assets); never assign the same asset to two slots; respect `hysteresis_bars` (do not evict
a freshly-taken slot to chase a higher rank within the hysteresis window). READ how BLUE/the trader
manages `max_slots` (launcher venue config + engine) and transcribe the rule; if BLUE is
single-slot today (`max_slots=1`), the manager must still be correct + generalize to N.
**Pass criteria.** Held assets retained; free slots filled by rank; no double-occupancy; hysteresis
prevents churn; max_slots respected. Hypothesis: |HELD slots| ≤ max_slots always; no asset in two
slots. No edits outside the 2 files.
## TASK 34 — Capital allocation across slots
**Why.** Turn slot occupancy + conviction into per-slot capital + notional, honoring BLUE's sizing
convention (notional = base_fraction × conviction × capital) and the margin-study findings.
**Affected files (NEW):** `prod/clean_arch/violet/selection/capital_allocator.py`,
`prod/clean_arch/violet/selection/test_violet_capital_allocator.py`.
**Interface/approach.** First READ how BLUE allocates capital across concurrent slots (shared pool
vs per-slot; the margin study `blue_margin_envelope_study` + `sizing.py` are the references —
notional = 0.20 × conviction × capital; capital under-utilized at 1 slot was DELIBERATE). Define
`allocate(slots: list[SlotState], convictions: dict[Symbol, float], *, capital: float, base_fraction:
float) -> list[CapitalAllocation]` reproducing that convention EXACTLY (cite the source). Do NOT
invent a normalization BLUE doesn't do.
**Pass criteria.** Per-slot notional == base_fraction × conviction × capital (the documented model);
sum-of-notionals behavior matches BLUE's (shared-capital, not artificially normalized, unless BLUE
normalizes — verify); poison guards reject non-finite/negative. Cite the allocation source. No edits
outside the 2 files.
## TASK 35 — Selection→slot→intent multi-asset flow harness (DARK)
**Why.** Compose the V5 path end-to-end: `rank_pipeline``slot_manager``capital_allocator`
(existing sizing) → `ExecIntent` per occupied slot (PASS-4 Task 17), DARK.
**Affected files (NEW):** `prod/clean_arch/violet/selection/multi_asset_flow.py`,
`prod/clean_arch/violet/selection/test_violet_multi_asset_flow.py`.
**Interface/approach.** `run_selection_cycle(market_data, held, *, factors, capital, policy, ...) ->
list[ExecIntent]` wiring the four units. Reuse `sizing.VioletSizer` for conviction (import, don't
fork). DARK: emits intents, never orders. Deterministic.
**Pass criteria.** A multi-asset scenario yields one intent per occupied slot with correct
asset/qty/notional; held assets not re-entered (unless `allow_reentry`); max_slots respected
end-to-end; deterministic. No edits outside the 2 files.
## TASK 36 — Ranking bit-identity gate vs the real AlphaAssetSelector
**Why.** Pin the ranking to BLUE's actual `AlphaAssetSelector` over a sampled grid — the unit-level
parity that, once green, removes selection-math as a suspect for CRITICAL #1 (leaving timing/join as
the remaining live-aggregate suspect for Claude).
**Affected files (NEW):** `prod/clean_arch/violet/selection/test_violet_rank_parity_gate.py`; gate
report → `prod/VIOLET_dev/reports/violet_rank_parity_<UTC>.json`.
**Interface/approach.** Over many synthetic universes (varied asset counts, price histories,
directions, with/without OB), assert `rank_pipeline.rank_assets` produces the SAME ordering + the
SAME ARS/ob_adjusted scores (`==`) as a direct `AlphaAssetSelector` run on the same inputs. Record
mismatch count (must be 0).
**Pass criteria (`@pytest.mark.gate`).** ≥ 200 universes, zero ranking/score mismatches; report
archived. If mismatches appear, that IS a finding — report them, do not loosen. No edits outside the
new file.
---
## Composition map
```
contracts_v3 (+AssetRank/SlotState/CapitalAllocation/SlotPolicy)
32 rank_pipeline(market, ob, irp, stables) → [AssetRank] (faithful to AlphaAssetSelector + OB Sub-1)
33 slot_manager(ranked, held, policy) → [SlotState] (max_slots, hysteresis, no double-occ)
34 capital_allocator(slots, convictions, cap)→ [CapitalAllocation] (BLUE notional convention)
35 multi_asset_flow: 32→33→34→ sizing → [ExecIntent] (DARK V5 cycle)
36 rank_parity_gate: rank_pipeline == AlphaAssetSelector (bit-identity) ← narrows CRITICAL #1
```
Integration (running the V5 cycle on the live reactor, wiring intents to the PASS-5/6 exec stack) is
the OWNER's job later.
## Recommended order
**31 (contracts) → 32 (rank pipeline) → 36 (rank parity gate) → 33 (slots) → 34 (allocation) → 35
(flow harness)**. 36 right after 32 so the ranking is pinned before building on it.
## Still NOT in scope (operator/owner only, or Claude)
- **The live BLUE↔VIOLET aggregate parity root-cause (CRITICAL #1)** — Claude's job; this pass only
pins ranking-math + builds V5 units.
- **Alpha re-timing / sub-second actuation of entries** — VBT re-certification (research), not a unit.
- **DARK soak start; V4 live execution; HZ-bridge; VIBRISS.**
- Any edit to in-flight / shared files in §0.

View File

@@ -70,6 +70,12 @@ QUIRK-INJECTION gate that flips PASS-5's QuirkProfile flags ON and proves each h
the quirk. Mirrors PINK's production fixes (pink_direct.py). Real-key smoke still MANDATORY before the quirk. Mirrors PINK's production fixes (pink_direct.py). Real-key smoke still MANDATORY before
V4-live; review when done. V4-live; review when done.
**PASS 7**: `VIOLET_PART_SPEC_OA_TODO_PASS7.md` (issued 2026-06-17) — V5 selection (faithful
ARS/IRP ranking + OB Sub-1), multi-asset slot manager, capital allocation, multi-asset flow, and a
ranking bit-identity gate vs AlphaAssetSelector. NOTE: this layer is the suspected locus of CRITICAL
#1 — PASS 7 PINS the ranking math (narrowing the suspect to timing/join), but the live-aggregate
root-cause stays Claude's job. Review when done.
**Action:** review each pass for correctness, BLUE-algo compliance, V-TYPES, no-shared-edits, **Action:** review each pass for correctness, BLUE-algo compliance, V-TYPES, no-shared-edits,
real (non-vacuous) tests. **Owner: Claude (me), later.** real (non-vacuous) tests. **Owner: Claude (me), later.**