Files
siloqy/prod/docs/VIOLET_PART_SPEC_OA_TODO_PASS7.md
Codex 0ab83c528a 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>
2026-06-17 10:53:12 +02:00

12 KiB
Raw Blame History

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.pyAlphaAssetSelector.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. AssetRankasset: 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. SlotStateslot_id: int (ge=0), asset: Optional[Symbol], status: str ("FREE"/"HELD"/"PENDING"), held_since_ns: Optional[MonoNs].
  3. CapitalAllocationslot_id: int, asset: Symbol, allocated_capital: float (ge=0), notional_fraction: float (ge=0), conviction_leverage: float (ge=0).
  4. SlotPolicymax_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_pipelineslot_managercapital_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.

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.