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>
12 KiB
VIOLET — partial spec for another agent, PASS 7 (OA TODO): V5 SELECTION + MULTI-ASSET SLOTS + CAPITAL ALLOCATION
Date: 2026-06-17. Continues PASS 1–6 (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_scoreflow 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 1–6 — 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/(+ extendcontracts_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):
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"/"" ).SlotState—slot_id: int (ge=0),asset: Optional[Symbol],status: str("FREE"/"HELD"/"PENDING"),held_since_ns: Optional[MonoNs].CapitalAllocation—slot_id: int,asset: Symbol,allocated_capital: float (ge=0),notional_fraction: float (ge=0),conviction_leverage: float (ge=0).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_marketis 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) → markirp_passed/excluded_reason. - Stablecoin exclusion: any asset in
stablecoins→ excluded (must equaldecision_engine.STABLECOIN_SYMBOLS; assert in test). - Sort descending by
ob_adjusted_score; assignrank. Pure function, deterministic, V-TYPES out. Pass criteria. On crafted market data the ranked order + ARS/ob_adjusted scores match a directAlphaAssetSelectorcomputation; 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.