ORDER_MANAGER.PY — Architectural Map (Agent-5, Phase A)
Evidence base: forensic inventory at HEAD 0015608 (post Agent-4 winner-protection sprint 0839da3). No edits made during this phase. This document precedes any extraction (task brief §24).
1. Current shape
6372 LOC, 1 god class + 6 support types
| Item | Span | Notes |
|---|---|---|
| Module constants (18) | L60-155 | exposure caps, BE/giveback/trailing geometry |
| ExitMechanism (Enum) | L158 | exit taxonomy |
| PositionState (Enum) | L172 | 11 in-trade lifecycles |
| PositionEvaluationStep | L190 | trajectory step record |
| LSFTicketState | L209 | LSF per-ticket state |
| PositionProtectionState | L226 | per-ticket protection facts (dataclass) |
| SmartPositionMetrics | L281 | 57 derived metrics (dataclass) |
| OrderLifecycleManager | L348-6372 | 81 methods, 99 distinct self.* state attrs |
2. Responsibility map (evidence-verified, method-level)
| Responsibility | Methods (span) | State used | Ext. deps | Side effects |
|---|---|---|---|---|
| A. Order dispatch/submission | execute_order, dispatch_order, _clamp_dispatch_volume, count_total_exposure, _is_exposure_available | _processed_orders, _live_tickets_lock+cache, exposure consts | adapter, risk_engine, rule_matrix | BROKER order_send via adapter; audit rows; dedup tombstone |
| B. AI reversal / lifecycle actions | execute_ai_reversal, execute_lifecycle_action | entry context maps | adapter, notifier | broker; audit; telegram |
| C. Pending order mgmt | manage_pending_orders, should_modify_pending_order, _pending_broker_state, cancel_pending_order_verified/with_retry, reconcile_pending_state, _sweep_stale_pending_contexts, _emit_terminal_for_pending | _pending_orders_setup_time, _pending_cancel_reasons, _pending_context_registry | adapter, audit | broker cancel/modify; terminal outcomes |
| D. Position state machine | transition_state_with_hysteresis, _evaluate_candidate_state, _arbitrate_decision | _position_states, _state_transition_candidates (+ reads _sl_modified_flags, _recovery_*, protection state) | — | in-memory only |
| E. Protection geometry & SL mgmt | refresh_protection_state, get_protection_state, calculate_breakeven_sl, _is_sl_at_or_beyond, is_sl_improvement, _protective_sl_floor, apply_breakeven_lock, _maybe_tighten_protective_sl, _tiered_giveback_floor, evaluate_profit_giveback, enforce_profit_giveback_protection, apply_atr_trailing_stop, _should_modify_sl, _log_protection_audit | _protection_state, _sl_modified_flags, _last_modify_sl, _last_mod_price/time | adapter (order_modify), audit, notifier | broker SL modify; audit rows |
| F. Smart metrics / hold score | _calculate_smart_position_metrics, _calculate_hold_value_score, _recalculate_hold_score_with_position_state, _resolve_position_management_scenario, _calculate_protection_score, _calculate_adaptive_evidence_scores, _calculate_trajectory_features, _add_trajectory_step, _calculate_continuous_giveback_severity | _mfe/mae trackers, _time_* trackers, _stagnation/adverse/favorable ticks, _trajectory_history, _hold_score_tracker(+base/last_reasons) | FeatureVector | in-memory |
| G. Recovery mode | _initialize_recovery_mode, _evaluate_recovery_budget_and_horizon, _evaluate_minimum_loss_optimization | _recovery_* (6 dicts) | — | in-memory |
| H. Position loop orchestration | manage_active_positions (1465L) | reads nearly everything | adapter, audit, notifier | broker close/modify; persistence; telemetry |
| I. Fill/reconciliation | reconcile_missed_closes, refresh_live_tickets_cache, _is_closed_ticket, _broker_close_verified, _ensure_ticket_bootstrap, _update_lsf_desync_metrics, _update_tick_state | _live_tickets_cache, _reconcile_seen, _lsf_state | adapter, audit | broker reads; audit |
| J. Outcome/autopsy | _record_experience_outcome, _update_mfe_mae, _capture_reversal_state, _close_sibling_legs, _cleanup_ticket_state | experience_engine, lifecycle_tracker, ~45 per-ticket dicts | experience_engine, audit | experience ledger; state teardown |
| K. Telemetry/telegram | should_emit_console_telemetry, register_telegram_message, register_order_message, _send_telegram, _log_throttled_be_failure | notifier, _order_message_ids, _order_id_to_message_id, _last_telemetry_time | notifier | telegram (INV-010 read-only consumer) |
3. State ownership map (key structures)
| State | Writers | Readers | Lock | Lifecycle | Notes |
|---|---|---|---|---|---|
| _processed_orders | execute_order | execute_order | none (loop-thread only) | engine lifetime | order-id dedup tombstone |
| _live_tickets_cache | refresh/reconcile/manage/close | many | _live_tickets_lock (12 CS) | engine lifetime | the ONLY locked structure |
| _protection_state | get_protection_state (lazy init), refresh (via dataclass) | 12 sites via accessor; debug_snapshot via method | none | NOT in cleanup tuple; bounded by open tickets | access 100% through accessor |
| _position_states / _state_transition_candidates | transition_state_with_hysteresis only | evaluate_candidate, cleanup, live_engine(L4507), tests | none | cleanup tuple | state machine core |
| _sl_modified_flags | refresh, apply_breakeven_lock, _maybe_tighten, apply_atr_trailing, manage_active_positions, cleanup | evaluate_candidate, manage loop | none | cleanup tuple | mirrors broker truth |
| _recovery_* (6 dicts) | _initialize_recovery_mode, _evaluate_recovery_budget_and_horizon, cleanup | _evaluate_candidate_state, manage loop | none | cleanup tuple | recovery budget |
| ~40 per-ticket trackers | manage_active_positions, _record_experience_outcome, capture/update fns | cleanup tuple (single teardown) | none | atomic bundle teardown in _cleanup_ticket_state | THE cross-cutting invariant |
CRITICAL INVARIANT: _cleanup_ticket_state releases ~45 per-ticket dicts as ONE bundle, atomic with the close/autopsy path. Any state extraction must preserve this single teardown (or route through an explicit per-ticket state object).
4. Concurrency map
- SINGLE loop thread owns: dispatch, SL/TP management, state transitions, cleanup.
No asyncio, no worker threads inside order_manager (0 async methods, 0 Thread()).
- The ONE lock:
_live_tickets_lock(threading.Lock) protecting_live_tickets_cache
(12 critical sections) — shared with web reads (debug_snapshot) so the cache can be read from request threads.
- Hot-restart path: live_engine swaps
order_manager.adapter/mt5_adapter
(L5684-5703) — adapter replacement is externally driven.
- No queues, no timers of its own; telemetry cadence gated by monotonic time.
5. Order/position state machine (actual, from code)
PositionState (11 states): PROFIT_UNPROTECTED -> PROFIT_PROTECTED -> PROFIT_TRAILING; giveback branch PROFIT_GIVEBACK_WARNING <-> CRITICAL; loss branch LOSS_EARLY -> LOSS_RECOVERY_CANDIDATE -> CONFIRMED / FAILING -> LOSS_EXIT_PRESSURE -> LOSS_HARD_EXIT. Transitions go through transition_state_with_hysteresis (count-based + time-based debounce; emergency bypass: LOSS_HARD_EXIT / PROFIT_GIVEBACK_CRITICAL honored immediately, incl. on first observation). Candidate states are staged in _state_transition_candidates (target, now, count) until thresholds met.
Order-level idempotency: execute_order checks _processed_orders[order_id] BEFORE dispatch and tombstones after (both success AND failure outcomes), preventing duplicate submissions across reconciliation replays.
6. Broker boundary
ALL broker interaction flows through self.adapter (IMT5Port) — 21 call sites, no direct order_send anywhere in this file (grep = 0). Broker-touching methods: execute_order, dispatch_order, _clamp_dispatch_volume, execute_ai_reversal, execute_lifecycle_action, refresh_live_tickets_cache, _broker_close_verified, apply_breakeven_lock, _maybe_tighten_protective_sl, enforce_profit_giveback_protection, apply_atr_trailing_stop, manage_active_positions (10 sites), reconcile_missed_closes, _close_sibling_legs. The adapter contract (IMT5Port) is the existing boundary — no new adapter needed.
7. Persistence boundary
self.audit (AuditRepository) used in 19 sites: log_order (protection audit), experience/ledger writes via _record_experience_outcome, failure rows, terminal pending outcomes (via execution.terminal_outcome). Persistence calls inside dispatch/execution methods are part of execution invariants — they are NOT a separable persistence layer; only the protection-audit write is already isolated (_log_protection_audit).
8. Consumer / fan-in map
| Consumer | Symbol | Public? | Usage | Risk |
|---|---|---|---|---|
| application/live_engine | OrderLifecycleManager | public | constructs, wires adapter/audit/notifier/risk/experience, calls dispatch/manage/reversal/lifecycle; hot-swap adapter; reads _position_states, _hold_score_tracker, _safe_feature_float (de-facto private) | HIGH |
| web/debug_snapshot.py | get_protection_state, _live_tickets_cache | mixed | reads protection + live cache (locked) | MEDIUM |
| 15 test files | OrderLifecycleManager + PositionState + internals | de-facto public | construct with fakes; POKE PRIVATE DICTS directly (_hold_score_tracker, _entry_timestamps, _entry_prices, _entry_directions, _last_known_volume, _processed_orders, _live_tickets_cache, _last_reasons_tracker) | HIGH for any state relocation |
9. Candidate seams & decisions
| Seam | Cohesion | State ownership | Risk | Coupling reduction | Decision |
|---|---|---|---|---|---|
| S1 ProtectionLedger (PositionProtectionState + per-ticket dict + get/refresh) | HIGH (self-described per-ticket facts) | CLEAN: dict touched at 4 sites only; all external consumers via methods | LOW-MED | Removes dataclass+dict from god class; accessor stays | EXTRACT FIRST |
| S2 PositionStateMachine (_position_states + candidates + transition/evaluate) | HIGH logic | MEDIUM: reads _sl_modified_flags/_recovery_*/protection (cross-cluster reads) | MED | Real | EXTRACT LATER (after S1) |
| S3 RecoveryBudget (6 dicts + 2 fns) | HIGH | MEDIUM: read by evaluate_candidate | MED | Real | EXTRACT LATER |
| S4 SmartMetrics/hold-score calculators | HIGH (pure-ish) | LOW: read trackers; write trajectory | MED | High LOC, zero I/O | EXTRACT LATER |
| S5 dispatch/submit pipeline | HIGH | couples _processed_orders + exposure + risk | HIGH | — | KEEP in class |
| S6 manage_active_positions decomposition | — | reads everything | VERY HIGH | — | BLOCK (needs S1-S4 first) |
10. Recommended extraction order
S1 ProtectionLedger -> S3 RecoveryBudget -> S2 StateMachine -> S4 metrics. Each behind facade methods on OrderLifecycleManager; per-ticket teardown bundle preserved (ledger exposes drop_ticket(ticket) called from _cleanup_ticket_state).
11. Golden baseline
11 execution suites, pre-extraction: ALL PASS (see pytest_om_baseline.txt, RC=0) — order_lifecycle, execution_architecture, hardened_protocol, adaptive_position_management, winner_protection_geometry_sprint, order_manager_exit_bugs, trade_lifecycle_task3, lifecycle_bug140, log_autopsy_fixes, accounting_hedging, rule_matrix.
12. S2 PositionStateMachine — extraction record (Agent-5, post-S3)
- New modules: execution/position_states.py (the 11-state enum, single
source; facade re-exports), execution/position_state_machine.py (PositionStateMachine: _states + _candidates + transition_with_hysteresis, verbatim rules; hysteresis params injected via a getter — the machine owns state + rules, NOT config/broker).
- Facade: order_manager.transition_state_with_hysteresis is a one-line
delegate (same signature); compatibility @properties expose the machine's LIVE dicts under the historical names (_position_states / _state_transition_candidates) — live_engine's bool check and 6 test sites unchanged; cleanup calls _state_machine.drop_ticket() inside the atomic teardown.
- State graph (actual): first observation seeds a safe neutral state
(profit-side targets -> PROFIT_UNPROTECTED, else LOSS_RECOVERY_CANDIDATE) except emergency targets (LOSS_HARD_EXIT / PROFIT_GIVEBACK_CRITICAL) which bypass with zero latency incl. on first observation; same-state observation cancels the candidate; normal transitions require BOTH min_confirmation_duration AND min_observation_count (window never resets); confirmation logs [STATE MACHINE TRANSITIONED].
- Coupling before/after: the machine owns NO recovery/protection state —
evidence-based evaluate stage stays in the manager and READS budget remaining (S3 view) + SL-modified/protection facts; the machine receives only the resulting target state. Clean read-only/command boundary.
- Verification: 10-test golden (written pre-extraction against the original
methods, green post) + 12 execution suites RC=0; perf probe 1.634us per repeat-observation transition (O(1), no I/O).
- Remaining seams: S4 intelligence/metrics calculators; S6
manage_active_positions decomposition (last, after S4).
13. S4 PositionIntelligence (SmartMetrics kernel) — extraction record (Agent-5, post-S2)
- New module: execution/position_intelligence.py (356L) — SmartMetricsInputs
dataclass (every input explicit) + _safe_feature_float (NaN/inf guards) + _estimate_liquidation_impact (Almgren-Chriss, eta parameterized) + calculate_smart_metrics (241L kernel VERBATIM — all 57 metrics).
- Purity: zero self.* references, zero I/O, imports carry no broker/audit/
notifier surfaces (enforced by a golden source-scan test).
- Facade: order_manager._calculate_smart_position_metrics + the 3 helpers are
thin delegates building SmartMetricsInputs from self.*; 6 external call sites unchanged; formulas exist ONLY in the kernel.
- Coupling before/after: the kernel previously read 15+ manager attributes
inline; now the manager passes an explicit immutable input bundle — the intelligence has no reference to OrderLifecycleManager (no fake boundary).
- Units documented (price/ATR/spread in price units, USD via contract-size,
duration seconds) — NOT normalized.
- Parity: 57-key dict equality over representative/edge cases + NaN/inf
feature guards + thin-facade identity; perf 16.8us per full calculation.
- Correction disclosed: a regime= input erroneously added by the extraction
script (the original method never read features.regime_state) was caught by mypy pre-commit and removed — the kernel contains exactly the original 57 metrics.
- Remaining intelligence methods are STATE_MUTATING tracker writers
(hold-value score writes _rolling_spreads; trajectory/tick/MFE-MAE updaters) — they stay in the manager; extracting them is future work only with an explicit tracker-state owner.
- Next: S6 manage_active_positions decomposition (last, highest risk).
14. S6 manage_active_positions — dead-ticket autopsy sweep extraction (Agent-5)
- Forensic phase map (1435L method): account snapshot refresh; falling-knife
protection; live-tickets cache rebuild (the ONLY lock, 12 critical sections); Phase-14 reconcile close-loop (isolated); dead-ticket sweep + autopsy + experience outcome + teardown (~460L); rolling spread; per- position loop with 11 sections (bootstrap, protection refresh, tick trackers, entry-mod/partial-close [broker], throttled hold-score, trajectory+state, AI-flip [broker], protection priority chain, telemetry, rule-matrix, arbitration, CLOSE/MODIFY dispatch [broker+audit]).
- Side-effect ordering declared sacred and preserved: reconcile BEFORE
dead-sweep BEFORE no-positions return; protection priority chain order byte-identical; teardown bundle atomic.
- S6 seam extracted: _sweep_dead_tickets(symbol, positions, current_tick,
now, symbol_info, atr) — the vanished-ticket autopsy concern moved VERBATIM as a method extraction on the same object (no dependency change, no state duplication, no broker writes added). Call sits at the identical position. atr passed explicitly (derived pre-loop from feature_vector).
- Golden execution-trace tests (written PRE-extraction, green after):
vanished-ticket trace (deal lookup -> autopsy -> outcome -> teardown -> cache release), BUG-046 window anchoring (>=24h, <=7d), live-ticket survival. Characterization discovery: the Phase-14 reconcile close-loop probes deal history even with zero positions (test corrected to real behavior).
- Pre-existing unrelated failure proven via git worktree at pre-S6 commit:
closed-loop BUG-140 integration expects p0e-bug140-1 while BUG-185 moved the contract to p0e-bug185-1 (owner's lineage change, predates S6).
- Remaining in manage_active_positions: the per-position loop (bootstrap,
protection refresh, trackers, entry-mod/partial-close, throttled scoring, trajectory/state, AI-flip, protection chain, telemetry, rule-matrix, arbitration, dispatch). Future extractions require tracker-state ownership first (hold-value writes _rolling_spreads; trajectory/tick updaters).
15. S6-followup — PositionTrackingLedger: explicit tracking-state ownership
Phase-1 ownership audit (per-position loop, 935L at L4039-4974)
- 82 self.* names touched in-loop: 11 methods, 71 data fields; of the data
fields, 19 form the cohesive TRACKING cluster (all TICKET_LOCAL, keyed by ticket, zero external src consumers, few direct test seeds): tick/duration (_last_tick_timestamps, _time_in_profit_sec, _time_in_drawdown_sec, _peak_profit_usd [documented MIRROR of S1 protection.peak_win_usd], _peak_drawdown_usd, _last_tick_for_ticket), MFE/MAE (_mfe_tracker, _mae_tracker, _time_to_mfe_sec, _time_to_mae_sec), tick-state (_stagnation_ticks, _adverse_ticks, _favorable_ticks, _last_price_tracker), LSF desync (_lsf_state, _last_seen_ts), reversal evidence (_reversal_events, _entry_probs, _entry_regime_state).
- Everything else stays manager-owned: dispatch state
(_last_modify_sl, _sl_modified_flags, _forced_exit_mechanisms, _exit_pending_final_reason, _partial_closed_tickets), hold-score routing (_hold_score_tracker, _base_hold_score_tracker, _last_reasons_tracker, _last_hold_eval_time), telemetry throttle (_last_telemetry_time — SESSION_GLOBAL), spreads (_rolling_spreads — SESSION_GLOBAL), identity dicts (_entry_prices/_sls/_tps/... — lifecycle metadata), locks/cache.
- Writers of the tracking cluster are exactly: __init__, the five updaters,
the loop-head new-ticket seeding, the in-loop tick/duration block, _cleanup_ticket_state, and six well-defined readers (smart metrics, hold-value, sweep, experience, lsf get/set, scenario resolver).
Phase-2/3 — the boundary + lifecycle
- execution/position_tracker.py (385L): PositionTrackingLedger owns the 19
dicts + the five updaters (bodies verbatim) + record_tick_durations (the in-loop block verbatim) + drop_ticket. No broker/risk/policy/dispatch/ audit/persistence authority (source-scan golden enforces).
- Lifecycle: ensure_bootstrap -> CREATED (idempotent; MFE/MAE seed at ZERO
per ANOMALY-VERIFY-01) -> TRACKING (per-tick: record_tick_durations, update_lsf_desync_metrics, update_mfe_mae [entry anchor parameterized], update_tick_state, capture_reversal_state) -> drop_ticket -> CLEANED (atomic, called from the manager's cleanup bundle).
- Compatibility: order_manager keeps the historical dict names as @property
accessors returning the ledger's LIVE dicts (single source of truth; the cleanup tuple and direct test seeds keep working unchanged).
- Preserved original semantics (including quirks): _last_tick_for_ticket is
NOT released by cleanup (original leak kept); the stale-tick negative-delta pass still updates _last_tick_timestamps unconditionally; duration trackers self-seed at zero on first record (loop-head seeding parity).
Phase-4 seam + verification
- In-loop tick/duration block (24L) replaced by a single
_tracking.record_tick_durations call at the identical position — the first per-position loop extraction, enabled by explicit ownership.
- Gates: 18 suites RC=0 (S1-S6 goldens incl. 8 new ownership/lifecycle/
isolation tests + execution set); ruff/mypy/py_compile clean; perf 0.76-2.59 ms/pass (1 live position, mock adapter) — no material change.
- Remaining blockers for deeper loop decomposition: hold-score routing state
and dispatch state are interwoven with broker calls — next prerequisite is a tracker-owner decision for _hold_score_tracker/_base_hold_score_tracker (read-modify-write by the router) before arbitration/dispatch extraction.
16. S6-escalation — stage decomposition of the per-position loop
Four atomic commits, each independently gated (18-19 suites RC=0, ruff/mypy/ py_compile clean, perf unchanged):
- f2d8207 HoldScoreLedger (execution/hold_score_ledger.py) — explicit owner
of the four hold-score state dicts (_hold_score_tracker, _base_hold_score_tracker, _last_reasons_tracker, _last_hold_eval_time). Store-only boundary; manager keeps live-dict compat properties; cleanup bundle pops work unchanged. The previously identified blocker is resolved.
- c4d0aa8 DECISION STAGE — _decide_position_action(pos, ticket, ..., 17
explicit inputs) -> (action, scenario, rule_target_sl): rule-matrix evaluation, scenario fallback, multi-stage arbitration, exit-pending record, throttled exit-evaluation log, exit-mechanism mapping, giveback MFE-SL targeting (91L verbatim block). Broker dispatch stays manager-owned.
- 42b7964 TRACKING/EVIDENCE/STATE STAGE — _update_trajectory_and_state(...)
-> (pnl_features, evidence, confidence_factor, debounced_state, budget_exhausted): trajectory step, pnl features, adaptive evidence, recovery-budget gate on drawdown, candidate state, hysteresis debounce.
- 71ba47d HOLD-SCORE EVALUATION STAGE — _evaluate_hold_score(...) ->
(hold_score, invalidate_reasons, base_hold_score): throttled base eval, position-state recalculation, giveback override, tracker store.
Measured effect (baseline -> after):
- manage_active_positions: 966L -> 832L (-134L body; the three stages live as
explicit testable class methods adjacent to the orchestrator)
- self.* fields touched in-loop: 85 -> 68 (-17; hold-score state + decision
internals now behind stage signatures)
- internal stage calls in loop: 30 explicit stage invocations; branches
110 -> 91; try blocks 6 -> 4 in the loop body
- execution flow is now literally: ACCOUNT PREP -> TICKET DISCOVERY ->
TRACKING -> HOLD-SCORE EVAL -> POSITION EVAL (trajectory/evidence/state) -> PROTECTION/AI-FLIP chain -> DECISION -> DISPATCH -> TELEMETRY
Stage-method shape (Phase-5 target): each stage has an explicit typed input contract, a tuple return, no hidden globals, and preserves the exact statement order of the original block (verbatim moves). Broker writes remain only in the manager dispatch section.
Remaining: the loop body still holds the protection/AI-flip priority chain and the broker dispatch (~250L combined). Prerequisites documented: dispatch extraction requires an execution-plan object; protection-chain extraction requires the notifier-throttle owner decision.
17. S6-dispatch — ExecutionPlan + broker dispatcher extraction
- ExecutionPlan (execution/execution_plan.py): frozen dataclass capturing
the decision stage's intent — action (CLOSE | MODIFY_SL | PARTIAL_CLOSE | BREAK_EVEN | NORMAL_TRAIL), scenario, ticket, symbol, rule_target_sl, tagged mechanism. Intent only: no broker access, no risk/policy logic, no side effects; construction validated (non-empty action, positive ticket).
- Broker dispatcher: OrderLifecycleManager._execute_position_action(plan,
pos, ticket, now, atr, spread, min_stop_gap, price_current, rule_target_sl, hold_score, protection, symbol_info, current_tick, scenario, action) — the 175-line 5-branch dispatch moved VERBATIM from the per-position loop. Preserves: monotonic SL safety floor (loosening rule targets zeroed), _should_modify_sl gate, BUG-085 confirmed-modification tracking, BUG-087 broker-verified close ordering, forced-exit-mechanism tagging + failure pop, split-sibling propagation, partial-close guard, notifier calls with order-thread msg_id. The two trailing continue statements in the moved block were documented no-ops (dispatch was the loop's final section) and are annotated at their former sites.
- The manager remains the orchestrator: decision -> ExecutionPlan ->
dispatcher; the dispatcher never originates actions.
- Broker parity proven with spy-adapter goldens
(tests/unit/test_s6_dispatch_parity_golden.py): close_position called exactly once with ticket=; success path sets _closed_tickets + releases live-cache; failure path pops the mechanism; loosening MODIFY_SL zeroed (no broker call); improving MODIFY_SL calls modify_position with exact kwargs (ticket, stop_loss, take_profit) and advances _last_modify_sl + _sl_modified_flags per BUG-085.
- Measured: manage_active_positions 832L -> 684L; loop self.* fields
68 -> 61; branches 91 -> ~60 (dispatch branches moved); perf 0.73 ms/pass (1 live position) — no regression; 20 suites RC=0.
NEXT_SEAM (implementation-ready): Protection / AI-flip chain (~130L)
- state owner: protection refresh already delegates to the S1 ledger; the
chain's remaining shared state is the notifier throttle (_last_telemetry_time — shared with the institutional-telemetry block) and _sl_modified_flags/_last_modify_sl (dispatch-owned, read here).
- inputs: pos, protection snapshot, smart_metrics, evidence, hold_score,
atr, spread, price_current, feature_vector, probs, regime_state, now, current_time, min_stop_gap, symbol_info.
- outputs: (prot_score, ai_flip_detected, forced-mechanism tags mutated on
the manager as today).
- side effects: notifier.notify_* calls (throttled), _forced_exit_mechanisms
writes, _capture_reversal_state (tracker), state transitions via the S2 machine.
- blocking dependency: extract the notifier-throttle owner first (a 3-line
session-scoped throttle object) so the chain and telemetry share one owner; then the chain becomes a stage method with the same verbatim-move pattern used here.
18. S6 autopilot — telemetry throttle, protection chain, autopsy pipeline
Three seams extracted in one continuous verified pass (each independently gated: 21 suites RC=0, ruff/mypy/py_compile clean):
- TelemetryThrottle (execution/telemetry_throttle.py, STEP A) — explicit
owner of the BUG-129 shared per-ticket emission gate (_last_telemetry_time). API: may_emit / last_emit / record / drop_ticket. Manager keeps a live-dict compat property; the legacy never-firing lazy-init guard inside the loop was replaced by a throttle read (identical semantics — the guard could not fire after __init__ construction). 9 goldens.
- Protection/AI-flip chain (STEP C) — _run_protection_chain(pos, ticket, ...,
20 explicit inputs) -> bool: AI direction flip + fast-reversal dispatch (adapter.place_pending_order — the chain's broker authority is documented and remains manager-owned), deterministic priority chain, giveback enforcement, breakeven lock, MFE giveback trailing lock, throttled institutional telemetry. The block's 4 continue sites return skip=True; the caller continues the loop — identical control flow. (264L method.)
- Per-ticket autopsy pipeline — _autopsy_vanished_ticket(dead_ticket,
history_deals, symbol, now, current_tick, symbol_info, atr, hours_back): deal resolution (live window + BUG-088/089 durable fallback), the data-rich autopsy row, experience outcome, notification (418L verbatim, no accumulators/skips — iteration-independent). _sweep_dead_tickets is now a small coordinator (lookup + loop + finalize + cleanup).
Measured cumulative (S6 start -> now): manage_active_positions 966 -> 484L; loop self.* fields 85 -> 53; the orchestrator is now a linear sequence: account prep -> discovery -> tracking -> hold-score eval -> trajectory/evidence/state -> protection chain (skip signal) -> decision stage -> ExecutionPlan dispatch -> sweep call. All stages have typed input contracts and verbatim-preserved bodies; broker calls remain only in the chain (reversal dispatch), the dispatcher, and reconcile paths.
Largest remaining methods: manage_active_positions 484L (orchestrator), _autopsy_vanished_ticket 423L (could split row-build/experience later), _run_protection_chain 264L, reconcile_missed_closes 204L.
18. S6 autopilot — telemetry throttle, protection chain, autopsy pipeline
Three seams extracted in one continuous verified pass (each independently gated: 21 suites RC=0, ruff/mypy/py_compile clean):
- TelemetryThrottle (execution/telemetry_throttle.py, STEP A) — explicit
owner of the BUG-129 shared per-ticket emission gate (_last_telemetry_time). API: may_emit / last_emit / record / drop_ticket. Manager keeps a live-dict compat property; the legacy never-firing lazy-init guard inside the loop was replaced by a throttle read (identical semantics — the guard could not fire after __init__ construction). 9 goldens.
- Protection/AI-flip chain (STEP C) — _run_protection_chain(pos, ticket, ...,
20 explicit inputs) -> bool: AI direction flip + fast-reversal dispatch (adapter.place_pending_order — the chain's broker authority is documented and remains manager-owned), deterministic priority chain, giveback enforcement, breakeven lock, MFE giveback trailing lock, throttled institutional telemetry. The block's 4 continue sites return skip=True; the caller continues the loop — identical control flow. (264L method.)
- Per-ticket autopsy pipeline — _autopsy_vanished_ticket(dead_ticket,
history_deals, symbol, now, current_tick, symbol_info, atr, hours_back): deal resolution (live window + BUG-088/089 durable fallback), the data-rich autopsy row, experience outcome, notification (418L verbatim, no accumulators/skips — iteration-independent). _sweep_dead_tickets is now a small coordinator (lookup + loop + finalize + cleanup).
Measured cumulative (S6 start -> now): manage_active_positions 966 -> 484L; loop self.* fields 85 -> 53; the orchestrator is now a linear sequence: account prep -> discovery -> tracking -> hold-score eval -> trajectory/evidence/state -> protection chain (skip signal) -> decision stage -> ExecutionPlan dispatch -> sweep call. All stages have typed input contracts and verbatim-preserved bodies; broker calls remain only in the chain (reversal dispatch), the dispatcher, and reconcile paths.
Largest remaining methods: manage_active_positions 484L (orchestrator), _autopsy_vanished_ticket 423L (could split row-build/experience later), _run_protection_chain 264L, reconcile_missed_closes 204L.
18.1 Entry-sync stage (autopilot continuation)
- _sync_external_modifications(pos, ticket, price_current, symbol_info):
broker-side SL/TP/volume modification detection + notifier + BUG-045 tracker advance + partial-close realized-pnl computation (71L verbatim). manage_active_positions: 484 -> 416L; loop self-state 53 -> 52.
- Remote-race note: d07a2a3 (entry-sync) was committed while Nexus-Docs
c1f8bee landed (site/_site re-tracking tug-of-war); resolved via clean merge e89681d; unrelated unstaged foreign WIP left untouched; HEAD == origin/main verified at each step.
19. S6 verification closure + stop-rule application
Verification (directive conditions 1-8)
- FINAL_HEAD at verification time: dd857f3; remote subsequently advanced by
parallel owners (331b4b3, f8c2225) — all S6 commits (6c97bc7, 77295ea, 3a97cef, dd857f3) verified IN-ANCESTRY of the advancing HEAD.
- TicketsCache regression fix independently verified: the
_live_tickets_cache @property exists (reads _tickets_cache.cache — storage-identity proven), ZERO shadowing assignments remain, swap()/ pop_ticket() are the only publication paths (refresh, rebuild, cleanup).
- Full 22-suite regression at FINAL_HEAD: all S6-owned suites green; ONE
failure (test_accounting_hedging hedging-order) proven PRE-EXISTING at dd857f3 via git worktree (foreign accounting/market-calendar lineage: 744b62fd/4e6beedb/b396ef0e) — not S6-owned.
- Commit scope audit: S6 commits touch only order_manager.py + new S6
modules + S6 goldens + architecture doc + taskboard. The one absorption (56a0316: 470 pre-staged deletion-only artifact removals) is disclosed.
- Release provenance: any artifact built from 77295ea is superseded;
builds must come from the exact FINAL_HEAD at acceptance time with source==provenance==build-info==runtime commit.
Stop-rule application: VanishedTicketAutopsy NOT extracted
Evidence (measured, not assumed):
- The analysis span reads 13+ per-ticket dicts and performs an in-span
STATE MUTATION (self._forced_exit_mechanisms.pop) plus float()-wrapped tracker reads with cross-field dependencies (initial_sl_val feeding final_sl_val/was_sl_modified).
- A zero-callback component would require either live-dict passing
(hidden state access, authority leak) or an evidence bundle + a mutation callback (boundary-warping, plus 5+ callbacks through the exception-isolation choreography).
- Per the directive: EXTRACTION STOPPED. The 423L phase method remains
INTACT and remains the documented owner of the vanished-ticket choreography (resolve -> outcome -> row -> experience -> notify -> teardown). Its internal split into dict-returning sub-stages was also rejected (same warp in weaker form).
Remaining seams (evidence-ranked, for the next task)
- reconcile_missed_closes (204L) — restart-gap close-loop; independent of
the loop; shares the autopsy/experience path. Medium candidate.
- _run_protection_chain (264L) — extractor blocked on the notifier-throttle
owner (DONE: TelemetryThrottle) — the chain is now stage-extractable with an explicit skip-signal contract (already done in this cycle).
- manage_active_positions (378L) — now a linear typed-stage orchestrator;
further reduction requires dispatch-plan enrichment, not extraction.