
    j                        U d Z ddlmZ ddlZddlZddlZddlmZ ddlmZm	Z	 ddl
mZ ddlmZ dddddd	d
dddd
Zded<   dZddZddZddZddZddZ G d d      Zy)u	  
APEX V16/V18 — Dashboard state writer.

Atomic JSON snapshot emitted every maintenance tick to feed an
external dashboard / TUI / web view. The file is overwritten in place
(no rotation, no history): a single consumer reads the latest tick.

Design constraints:
  - Fail-open: a write error MUST NOT break the orchestrator loop. All
    public entry points are wrapped; on failure we log a warning via
    orchestrator._sys_log and return.
  - Atomic: write to a temp file in the same directory, fsync, rename.
    A reader can mmap/open the target file without ever seeing partial
    JSON.
  - Read-only on orchestrator state: the writer never mutates anything
    on the orchestrator or on the SessionState; it only reads fields.

Snapshot layout (top-level keys):
  version, generated_at, mode
  session    : balance / equity / unrealized / session_pnl / halts / iter
  daily      : DailyCounters serialised (date + counters)
  brain_stats: MR / TF wins-losses-trades-win_rate + bias_calls_count
  asset_stats: per-symbol trades/wins/losses/pnl/win_rate aggregated
               by *completed trade* (partial_close + balance_confirmed
               fused into one trade per entry). Wins/losses are
               decided on the trade's TOTAL P&L, so a +$X partial
               followed by a BE residual counts as one WIN, not 1W+1S.
  asset_stats_today: same shape as asset_stats but filtered to trades
               whose full close ts falls on the active session day
               (daily.date prefix).
  trade_history: chronological list of realized P&L points — one row
                per completed trade at the full-close ts. kind is
                "win"/"loss"/"scratch" by total trade P&L; has_partial
                flags trades that bundled a partial leg.
  trade_history_daily: trade_history rolled up per UTC calendar day —
                one entry per day with pnl_day + cumulative_pnl (gross
                and net), in ascending date order. Feeds the dashboard
                equity curve (one chart point per day).
  positions  : list of open trades (entry+runtime fields per symbol)
  events     : last N events merged from all JSONL streams (desc by ts)
  feed       : per-stream tail (candle/brain/order/risk/sys)

JSONL stream -> dashboard stream mapping:
  regime_log.jsonl   -> "candle"
  brain_log.jsonl    -> "brain"
  trade_log.jsonl    -> "order"
  session_log.jsonl  -> "risk"  (risk_manager logs rejections here)
  error_log.jsonl    -> "sys"
    )annotationsN)deque)datetimetimezone)Path)OptionalgQ@gףp=
@gp=
ף @gGz?)
6A6B6C6E6JMGCMCLMESMNQMYMzdict[str, float]COMMISSION_RT   c                J    | y 	 t        |       S # t        t        f$ r Y y w xY wN)int	TypeError
ValueErrorvalues    '/home/work/apex_v16/dashboard_writer.py
_parse_intr   K   s0    }5zz"    
 ""c                J    | y 	 t        |       S # t        t        f$ r Y y w xY wr   )floatr   r   r   s    r   _parse_floatr!   T   s0    }U|z" r   c                x    t         j                  |       }|y|rt        |      nt        }|dk  rt        }||z  S )N        r   )r   getr   _DEFAULT_CONTRACTS)symbol	contractsratens       r   _commission_forr*   ]   s=    V$D|#I);AAv!8O    c                 d    t        j                  t        j                        j	                         S r   )r   nowr   utc	isoformat r+   r   _utc_isor1   k   s    <<%//11r+   c                   |dk  s| j                         sg S 	 | j                  dd      5 }t        ||      }ddd       g }D ]M  }|j	                         }|s	 t        j                  |      }t        |t              s=|j                  |       O |S # 1 sw Y   _xY w# t        $ r g cY S w xY w# t
        j                  $ r Y w xY w)zReturn up to `n` most-recent valid JSON records from a JSONL file.

    Best-effort: missing file, OS errors, and malformed lines are
    silently skipped. Newest line ends up last in the returned list
    (file order preserved).
    r   rutf-8encoding)maxlenN)existsopenr   OSErrorstripjsonloadsJSONDecodeError
isinstancedictappend)pathr)   flinesoutlinerecs          r   _tail_jsonlrH   o   s     	AvT[[]	YYsWY- 	'!A&E	' C 	zz|	**T"C c4 JJsO	 J	' 	' 	 ## 		s9   B$ BB$ B5B!B$ $B21B25C
Cc                     e Zd ZU dZ ed      ZddddddZd	ed
<   	 d%ddd	 	 	 	 	 	 	 d&dZd'dZ	d(dZ
ed)d       Zed*d       Zed+d       Zed,d       Zed(d       Zed(d       Ze	 	 	 	 	 	 d-d       Zed.d       Zed/d       Zedd	 	 	 	 	 d0d       Zed/d       Zed1d       Zed2d        Zd.d!Zd3d"Zd4d#Zed5d$       Zy)6DashboardWriterzAAtomically writes a dashboard JSON snapshot per maintenance tick.z~/apex_v16/dashboard_state.jsonzregime_log.jsonlbrain_log.jsonlztrade_log.jsonlzsession_log.jsonlzerror_log.jsonl)candlebrainorderrisksyszdict[str, str]_FEED_FILESN2      )recent_events_limit
feed_limitc                   |t        |      n| j                  }|j                         | _        t	        |      | _        t	        |      | _        y r   )r   DEFAULT_OUTPUT
expanduseroutput_pathr   rT   rU   )selfrY   rT   rU   rB   s        r   __init__zDashboardWriter.__init__   sC     %0$;tK ATAT??,#&':#; j/r+   c                    	 | j                  |      }	 | j                  |       y# t        $ r}| j                  |d|        Y d}~yd}~ww xY w# t        $ r}| j                  |d|        Y d}~yd}~ww xY w)z8Build + atomically replace the snapshot file. Fail-open.zbuild failed: Nzwrite failed: )_build	Exception_warn_atomic_write)rZ   orchestratorsnapshotes       r   writezDashboardWriter.write   s{    	{{<0H	;x(	  	JJ|~aS%9:	
  	;JJ|~aS%9::	;s+   & A 	AA		A	A9A44A9c                   t        |dd       }t        |dd       }| j                  |      }t        t        |dd      xs d      }t        t        |dd      xs d      }t        |dd       }t        t        |dd      xs d      }t        |dd       }	|	t        |	      }
d	}n|}
d
}| j                  |      }||z   }t	        t        |dd      xs d      }| j                  ||      }dt               | j                  |      t        |d      t        |d      t        |d      t        |d      t        |
d      |t        |d      |d   t        |
|d   z
  d      t        t        |dd            t        |dd      xs dt        t        |dd            | j                  t        |dd             t        t        |dd      xs d      t        t        |dd      xs d      d| j                  |      | j                  t        |dd             |d   |d   |d   |d   | j                  |      | j                  |      | j!                  |      dS )Nstateconfig_cached_account_balancer#   session_pnldaily	daily_pnl_cached_daily_rpnlbroker_rpnlcounterdate r      daily_commissionshaltedFhalt_reason_broker_degraded_degraded_since
_iterationr   _maintenance_iter)balanceequityunrealized_pnl_usdri   rk   daily_pnl_sourcedaily_pnl_counterrr   daily_pnl_netrs   rt   broker_degradeddegraded_since	iterationmaintenance_iterrM   asset_statsasset_stats_todaytrade_historytrade_history_daily)versiongenerated_atmodesessionrj   brain_statsr   r   r   r   	positionseventsfeed)getattr_log_dirr    _sum_unrealizedstr_closed_trades_sectionr1   _moderoundbool_dt_isor   _daily_dict_brain_stats
_positions_recent_events	_raw_feed)rZ   orchrf   rg   log_dirry   ri   rj   counter_pnlrm   rk   r|   
unrealizedrz   
daily_datecloseds                   r   r]   zDashboardWriter._build   sd   gt,x.--'&?ELMGE=#>E#Fw- GE;<CDd$8$?"k*I,#I())%0
:%39r:
,,WjA $JJJv& !,*&+J&:$[!4"9a0$4%*;%:%+,?%@!&y6:M3N'NPQ!Rwuh>?&umR@FB#'6H%(P#Q"&,,wt=NPT/U"V |Q!?!D1E$'6I1(M(RQR$S" %%e,,,WUGT-JK!-0!'(;!<#O4#)*?#@/))'2NN7+;
 	
r+   c                N    t        | dd       }|yt        |dt        |            S )Nr   rp   r   )r   r   )rg   r   s     r   r   zDashboardWriter._mode   s+    vvt,<tWc$i00r+   c                :    t        | dd       }|rt        |      S d S )Nr   )r   r   )rg   r   s     r   r   zDashboardWriter._log_dir  s!    &)T2 'tG}1T1r+   c                ^    | y t        | t              r| j                         S t        |       S r   )r?   r   r/   r   r   s    r   r   zDashboardWriter._dt_iso  s+    =eX&??$$5zr+   c           	         | yd}t        | di       j                         D ]/  }t        |dd       }||t        t        |dd      xs d      z  }1 |S )Nr#   active_tradesruntimenet_profit_usd)r   valuesr    )rf   totalatrts       r   r   zDashboardWriter._sum_unrealized  sm    =%"5<<> 	FBY-BzU72'7=DEEE		F
 r+   c                D   | i S t        | dd      t        t        | dd      xs d      t        t        | dd      xs d      t        t        | dd      xs d      t        t        | dd      xs d      t        t        | d	d
            t        t        | dd
            dS )Nro   rp   rk   r#   approved_countr   executed_countrejected_countdaily_loss_hard_stop_hitFprofit_target_hit)ro   rk   r   r   r   r   r   )r   r    r   r   )rj   s    r   r   zDashboardWriter._daily_dict   s    =IE62.wuk3?F3G!'%1A1"E"JK!'%1A1"E"JK!'%1A1"E"JKWU$>FGWU$7?@

 
	
r+   c           	     v   d
d}| dddd ddddd dddS t        t        | dd      xs d      }t        t        | dd      xs d      }t        t        | dd      xs d      }t        t        | dd      xs d      }||||z    |||      d||||z    |||      dt        t        | d	d      xs d      dS )Nc                8    | |z   }|dkD  rt        | |z  d      S d S )Nr      )r   )wltots      r   _ratez+DashboardWriter._brain_stats.<locals>._rate2  s'    a%C(+a5S!$9T9r+   r   )winslossestradeswin_rate)mrtfbias_calls_countmr_wins	mr_lossestf_wins	tf_lossesr   )r   r   r   r   returnOptional[float])r   r   )rM   r   mr_wmr_ltf_wtf_ls         r   r   zDashboardWriter._brain_stats0  s    	: = AM AM$% 
 75)Q/41575+q16Q775)Q/41575+q16Q7 +5t3D
 +5t3D !$GE3Eq$I$NQ O

 
	
r+   c                x   | j                  |      }| j                  |      }d}|rT|D ]O  }t        |j                  dd            j	                  |      s.|t        |j                  dd      xs d      z  }Q | j                  |      | j                  ||      || j                  |      t        |d      dS )ux  Single-pass source of closed-trade stats from brain_log.jsonl.

        trade_log.jsonl is never written in V18 — realized P&L surfaces
        as two events in brain_log.jsonl:
          * `balance_confirmed`: emitted by _handle_exit and
            _check_external_close after a FULL close (broker balance
            snapshot, pnl reconstructed from consecutive deltas).
          * `partial_close`: emitted by _handle_partial_close on a 50%
            partial fill — broker balance is NOT snapshotted here, so
            the row carries `partial_pnl_usd` directly. Walking both
            event types in ts order, we keep a single rolling
            `prev_balance` cursor and treat each partial pnl as if it
            updated the cursor by the same amount the broker did
            (gross delta).

        We read the file once (it's large; ~26 MB / 90 k lines in
        production) and pass the parsed event list to asset_stats,
        asset_stats_today and trade_history.

        `daily_date` is the active CME session day (YYYY-MM-DD) — used
        both to filter asset_stats_today and to sum daily_commissions.
        r#   tsrp   commission_usd	ts_prefixrq   )r   r   r   r   rr   )	_realized_events_trade_historyr   r$   
startswithr    _asset_stats_trade_history_dailyr   )clsr   r   r   history
daily_commrows          r   r   z&DashboardWriter._closed_trades_sectionL  s    4 %%g.$$V,
 OswwtR()44Z@%0@#(F(M#"NNJO ++F3!$!1!1&J!1!O$#&#;#;G#D!&z1!5
 	
r+   c                   | g S | dz  }|j                         sg S g }i }	 |j                  dd      5 }|D ]  }|j                         }|s	 t        j                  |      }t        |t              s>|j                  d      }|j                  d      }|sc|j                  dd	      xs d	}	|d
k(  r~|j                  d      }
|
	 t        |
      }|j                  ||	d|dt        |j                  d            t        |j                  d            |j                  d      xs d	d       |dk(  r|j                  d      }|	 t        |      }|j                  ||	dd|t        |j                  d            t        |j                  d            |j                  d      xs d	d       |dk(  s|j                  d      }|	 t        |      }|	t        |      dd f}||j                  d      xs d	d||<    	 ddd       |D ]E  }|d   dk7  r|d   t        |d         dd f}|j                  |      }|6|d   |d<   |d   |d<   G |j#                  d        |S # t        j
                  $ r Y Uw xY w# t        t        f$ r Y kw xY w# t        t        f$ r Y w xY w# t        t        f$ r Y w xY w# 1 sw Y   xY w# t         $ r g cY S w xY w)u  Parse `balance_confirmed` + `partial_close` events, with the
        matching `pnl_discrepancy` payload attached when present.

        Returns a single list sorted ascending by ts, with a normalized
        schema:
          {ts, symbol, kind, balance_post, partial_pnl_usd, contracts,
           broker_pnl, pnl_source}
        where:
          * `kind` is "full" for balance_confirmed (balance_post set,
            partial_pnl_usd None) and "partial" for partial_close
            (balance_post None, partial_pnl_usd set).
          * `broker_pnl` is the `estimated_pnl` from a `pnl_discrepancy`
            event paired with the same balance_confirmed (orchestrator
            emits the two back-to-back microseconds apart for the same
            symbol when |broker_pnl − balance_delta| > $5). Consumers
            should prefer it over the balance delta — the broker value
            is much closer to TopstepX reality than the often-stale
            balance_post snapshot (0.5s settle window is not always
            enough for `get_account_balance` to reflect the close).
          * `pnl_source` is the discrepancy's `pnl_source` field:
            "broker" when the bot recovered the pnl from
            `recent_trades` (true broker value), "" / missing when it
            came from the closer's tick math.
          * `broker_pnl` is None when no discrepancy fired for that
            close (delta ≤ $5 — balance delta is trustworthy).

        partial_close events have no broker_pnl shadow today because
        orchestrator does not call recent_trades on the partial path;
        `partial_pnl_usd` (the closer's tick math) is the best signal
        available. Fail-open: missing file / OS errors → [].
        NrK   r3   r4   r5   eventr   r&   rp   balance_confirmedbalance_postfullr'   broker_pnl_usd
pnl_source)r   r&   kindr   partial_pnl_usdr'   
broker_pnlr   partial_closer   partialcontracts_closedpnl_discrepancyestimated_pnl   )r   r   r   r   c                    | d   S )Nr   r0   r3   s    r   <lambda>z2DashboardWriter._realized_events.<locals>.<lambda>  s
    !D' r+   )key)r8   r9   r;   r<   r=   r>   r?   r@   r$   r    r   r   rA   r   r!   r   r:   sort)r   rB   r   discrepanciesrC   rF   rG   ev_namer   r&   bpbp_fpppp_fepep_fr   evds                      r   r   z DashboardWriter._realized_eventsu  sQ   B ?I**{{}I 68L	31 IQ HD::<D !"jj. &c40 !ggg.GB  WWXr28bF"55 WW^4:$%#(9D "$&,$*,0/3)3CGGK4H)I +7sww?O7P*Q*-'',*?*E2'  !O3 WW%67:$%#(9D "$&,$-,0/3)3CGG<N4O)P +7sww?O7P*Q*-'',*?*E2'  !$55 WW_5:$%#(9D  &s2ws|4*.*-'',*?*E2.c*KHI^  	3B&zV#h<RXs!34C!!#&A}#$\?< #$\?< 	3 	)*c  // ! !  !*:6 %$%. !*:6 %$%* !*:6 %$%GI IT  	I	s   K KI6$A%K
JA8KJ&A$K?KJ< .KK 6J	KJKJ#K"J##K&J95K8J99K<KKKKKK K,+K,c                   g }d}i }|D ]r  }|d   }|d   }|dk(  r||d   }|j                  d      }|j                  d      xs d}	||	d	k(  r|}
||
z  }n|d   |z
  }
|d   }|j                  |d      }|r,|d
   |
z   }|d   t        ||j                  d            z   }d}n|
}t        ||j                  d            }d}|dkD  rdn|dk  rdnd}|j                  |d   ||||||z
  |d       ||j                  d      }|j                  d      xs d}	||	d	k(  r|}n|d   }||z  }t        ||j                  d            }|j	                  |ddd      }|d
xx   |z  cc<   |dxx   |z  cc<   u |S )a  Fuse partial + full close events into per-trade rows.

        A "trade" is one entry's full lifecycle: zero or more
        partial_close events on a symbol followed by exactly one
        balance_confirmed (full close) that closes the residual. We
        walk the realized events in chronological order, buffering
        partials per symbol, and emit one row when the matching full
        close arrives:
          pnl_usd     = sum_of_partial_pnls + (balance_post - prev_balance)
          commission  = sum of estimated round-trip commissions on each
                        leg (partial contracts_closed + full contracts)
          pnl_net     = pnl_usd - commission
          kind        = "win"  if pnl_usd > 0
                        "loss" if pnl_usd < 0
                        "scratch" if exactly 0 (rare; usually BE residual
                        after a winning partial still resolves > 0)
          ts          = the full close's ts (trade-completion timestamp)
          symbol      = the symbol of the trade
          has_partial = True if any partials were rolled into this row

        This wins/losses on the *total* trade P&L, so a +$50 partial
        followed by a $0 BE residual collapses to one WIN, not one
        WIN + one LOSS (or one WIN + one SCRATCH).

        The first full event with no prior baseline seeds the rolling
        cursor and is not emitted; in-flight trades (partials with no
        matching full close yet) are also not emitted.
        Nr&   r   r   r   r   r   rp   brokerpnl
commissionr'   TFr   winlossscratchr   )r   r&   r   pnl_usdr   pnl_nethas_partialr   r#   )r   r   )r$   popr*   rA   
setdefault)r   r   rE   previnflightr   r&   r   r   r   full_pnlbucketr   r   r  outcomepcommbs                      r   _build_tradeszDashboardWriter._build_trades  s   <  $$& H	(B\Ff:Dv~<n-D  VVL1
VVL17R
)jH.D)HH$D!.1D8Hn-D!fd3"(-(":G"("6{ 3:5 #5J"&K"*G"1&"&&:M"NJ"'K%,q[5%,q[6$  

T($#&&0&3#.  <   VVL1
VVL17R
)jH.D"A,-A	&vrvvk/BC''Cs;=%A,4'QH	(R 
r+   rp   r   c          
     N   i }| j                  |      D ]  }|rt        |d         j                  |      s#|d   }|s+|j                  |dddddd      }|dxx   dz  cc<   |d   dkD  r|d	xx   dz  cc<   n|d   dk  r|d
xx   dz  cc<   |dxx   |d   z  cc<   |dxx   |d   z  cc<    |j	                         D ]a  }|d   }|d	   }t        |d   d      |d<   t        |d   d      |d<   t        |d   |d   z
  d      |d<   |dkD  rt        ||z  d      nd|d<   c |S )a  Per-symbol aggregates over completed trades.

        Walks the realized events, fuses partial+full into per-trade
        rows via `_build_trades`, then aggregates by symbol. Wins and
        losses are decided on the *total trade* P&L, so a partial
        profit followed by a BE residual counts as one WIN (the prior
        per-event accounting would have split it into 1W + 1S).

        `ts_prefix` filters which trades are accumulated, using the
        full-close ts as the trade's completion timestamp. Pre-window
        trades still consume the rolling balance cursor (so the in-
        window trades' balance deltas remain correct).
        r   r&   r   r#   )r   r   r   r   r   r   r   r   r   r   r   r   rq   r  r   Nr   )r  r   r   r  r   r   )	r   r   r   statstrader&   r  r   r   s	            r   r   zDashboardWriter._asset_statsi  s   " "$&&v. 	@EU4[!1!<!<Y!G8_F%%a1s4F
 8!Y!#v!#y!A%x A% 5MU9--M#$.>(??$#	@$ lln 		FH%F&>D!&-3F5M',V4D-Eq'IF#$ %u'7 88!!=F9 ,2A:dVmQ'4 :		 r+   c                &   | j                  |      }g }d}d}|D ]t  }||d   z  }||d   z  }|j                  |d   |d   |d   |d   t        |d   d      t        |d      t        |d	   d      t        |d   d      t        |d      d
	       v |S )u  Equity-curve points — one row per *completed trade*.

        Same aggregation as `_asset_stats`: partial+full fused into one
        row at the ts of the full close, classified win/loss/scratch
        by total gross P&L. Running cumulative_pnl/cumulative_pnl_net
        are computed across rows so the chart can plot the equity
        curve directly without re-walking the underlying events.
        r#   r   r  r   r&   r   r  rq   r   )	r   r&   r   r  r   cumulative_pnlr   r  cumulative_pnl_net)r  rA   r   )r   r   r   rows
cumulativecumulative_netr  s          r   r   zDashboardWriter._trade_history  s     ""6*
 	E%	**JeI..NKKDk/f$]3 y!115"'
A"6"'.>(?"C y!115&+NA&>
 
	 r+   c                (   i }| D ]  }t        |j                  dd            }|dd }t        |      dk7  r2|j                  |ddd      }|dxx   t	        |j                  dd      xs d      z  cc<   |d	xx   t	        |j                  d
d      xs d      z  cc<    g }d}d}t        |      D ]\  }||   }||d   z  }||d	   z  }|j                  |t        |d   d      t        |d      t        |d	   d      t        |d      d       ^ |S )a  Roll up trade_history rows into one entry per UTC calendar day.

        ts is ISO-8601 with UTC offset, so the first 10 chars are the
        YYYY-MM-DD date in UTC. The chart consumes this directly: one
        x-axis tick per day, no per-trade clutter.
        r   rp   N
   r#   )pnl_daypnl_day_netr  r   r  r  rq   )ro   r  r  r  r  )r   r$   lenr  r    sortedrA   r   )	r  bucketsr   r   ro   r  rE   r  r  s	            r   r   z$DashboardWriter._trade_history_daily  s=    $& 	FCSWWT2&'Bcr7D4yB""4S)MNAiLE#'')S"9"@SAALmcggi&=&D EE	F 
7O 
	DA!I,&Ja..NJJ 9q1"'
A"6$Q}%5q9&+NA&> 	
	 
r+   c                P   | g S g }t        | di       j                         D ]   \  }}t        |dd       }t        |dd       }||&t        |dd       }t        t        |dd      xs d      }t        t        |dd      xs d      }|dkD  r|n|}	|j                  i d	|d
t        |dd      dt        |dd      dt	        t        |dd      xs d      dt        t        |dd      xs d      d|d|	dt        t        |dd      xs d      dt        |t              r|j                         n|t        |      nddt        t        |dd      xs d      dt        t        |dd      xs d      dt        t        |dd      xs d      dt        t        |dd            dt        t        |dd      xs d      dt        |dd      xs ddt        |dd      xs ddt        t        |dd            dt	        t        |dd      xs d      i        |S )Nr   entryr   	opened_atcurrent_sl_pricer#   sl_pricer   r&   rM   
brain_namerp   	directionr'   entry_pricetp_priceminutes_openprogress_pctr   partial_doneFr   last_brain_actionlast_brain_reasonis_paperconfidence_at_entry)
r   itemsr    rA   r   r?   r   r/   r   r   )
rf   rE   r&   r   r  r   r   
current_slsl_at_entryeffective_sls
             r   r   zDashboardWriter._positions  s   =I!%"=CCE %	JFBB.Eb)T2G}{D9Iww0BCHOCPJz3 ? F3GK)3a:[LJJ &b9 WUK< SQ!?!D1E	
 uWUM3%G%N3O K #L E'%S"A"HSI !)X6 '')'0'<S^" gg~s&K&Rs S gg~s&K&Rs S  !''+;SAHSI#$ WWne%L M%& "''+<cBIcJ)* $G%8"=C-. $G%8"=C12 D
E!BC34 &'<a@EAF7 %	L 
r+   c                N   || j                   dk  rg S g }| j                  j                         D ]Q  \  }}t        ||z  | j                         D ]0  }t	        |      }|j                  d|       |j                  |       2 S |j                  d d       |d | j                    S )Nr   streamc                &    | j                  dd      S )Nr   rp   )r$   r   s    r   r   z0DashboardWriter._recent_events.<locals>.<lambda>  s    !%%b/ r+   T)r   reverse)rT   rQ   r.  rH   r@   r  rA   r   )rZ   r   mergedr3  fnamerG   taggeds          r   r   zDashboardWriter._recent_events  s    ?d66!;I!--335 	&MFE"7U?D4L4LM &c!!(F3f%&	& 	14@00011r+   c           	     
   | j                   D ci c]  }|g  }}|| j                  dk  r|S | j                   j                         D ]3  \  }}t        t	        t        ||z  | j                                    ||<   5 |S c c}w )Nr   )rQ   rU   r.  listreversedrH   )rZ   r   kr   r3  r7  s         r   r   zDashboardWriter._raw_feed  s    6:6F6F&Gq"u&G&G?doo2K!--335 	MFEGeOT__=! DL	
  'Hs   
B c                   | j                   j                  j                  dd       t        j                  | j                   j
                  dz   dt        | j                   j                              \  }}	 t        |dd      5 }t        j                  ||d	t        
       |j                          	 t        j                  |j                                d d d        t        |      j!                  | j                          y # t        $ r Y 8w xY w# 1 sw Y   =xY w# t"        $ r- 	 t        |      j%                  d        # t"        $ r Y  w xY ww xY w)NT)parentsexist_ok.z.tmp)prefixsuffixdirr   r4   r5   F)ensure_asciidefault)
missing_ok)rY   parentmkdirtempfilemkstempstemr   r9   r<   dumpflushosfsyncfilenor:   r   replacer^   unlink)rZ   rb   fdtmp_pathrC   s        r   r`   zDashboardWriter._atomic_write!  s.   %%dT%B''##((3.D$$++,
H
	b#0 A		(AE3G	HHQXXZ(	 N""4#3#34     	X%%%6   	sf   8D  .D5#D,D  	DDDDDD   	E*EE	EEEEc                \    	 | j                   j                  d|       y # t        $ r Y y w xY w)Nz[dashboard] %s)_sys_logwarningr^   )r   msgs     r   r_   zDashboardWriter._warn<  s.    	MM!!"2C8 		s    	++r   )rY   zOptional[Path | str]rT   r   rU   r   r   None)r   rY  )r   r@   r   r   )r   Optional[Path])r   zOptional[str])r   r    )r   r[  r   r   r   r@   )r   r[  r   
list[dict])r   r\  r   r\  )r   r\  r   r   r   r@   )r  r\  r   r\  )r   r\  )r   r[  r   r@   )rb   r@   r   rY  )rX  r   r   rY  )__name__
__module____qualname____doc__r   rW   rQ   __annotations__r[   rd   r]   staticmethodr   r   r   r   r   r   classmethodr   r   r  r   r   r   r   r   r   r`   r_   r0   r+   r   rJ   rJ      s   K ;<N %##%##K  -1
* $&
*)
* !	
*
 
* 

* 
; <
D 1 1 2 2   	 	 
 
 
 
6 &
$&
25&
	&
 &
P E EN i iV 57--/2-	- -^  :  @ * *X2	6  r+   rJ   )r   Optional[int])r   r   )r&   r   r'   rd  r   r    rZ  )rB   r   r)   r   r   r\  )r`  
__future__r   r<   rN  rI  collectionsr   r   r   pathlibr   typingr   r   ra  r%   r   r!   r*   r1   rH   rJ   r0   r+   r   <module>ri     s|   0d #  	   '   d$
dT	#   2@r
 r
r+   