
    Uiwo                       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mZmZ ddl	m
Z
mZmZmZ ddlmZ ddlmZmZmZmZ dd	lmZmZmZmZ  ej4                  d
      Z G d d      ZddZej<                  j>                  dej@                  j>                  dejB                  j>                  dejD                  j>                  diZ#de$d<    G d d      Z%y)a  RLM Neo-Cortex -- Ebbinghaus Decay Scheduler.

Implements the forgetting curve: R = e^(-t/S)
where R = retention, t = time since last access, S = memory strength.

Manages:
  - Scheduled decay cycles (daily at 3 AM UTC)
  - Tier-specific decay policies (aggressive/moderate/conservative/infinite)
  - REM sleep consolidation (weekly on Sunday at 2 AM UTC)
  - Memory access tracking for spaced-repetition reinforcement
  - Dry-run mode for previewing decay operations

All storage uses Elestio PostgreSQL + Redis. NO SQLite. NO C: drive.
    )annotationsN)datetime	timedeltatimezone)AnyDictListOptional)UUID   )CustomerTierDecaySchedulerProtocolEntitlementManifest
MemoryTier)DECAY_POLICIEScalculate_retentioncalculate_strengthshould_decayzcore.rlm.decayc                  F    e Zd ZdZdZ	 d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZy)
_MemoryRowzIn-memory representation of a memory row during decay processing.

    This is an internal class -- not part of the public API. It mirrors
    the columns we read from PostgreSQL for decay calculations.
    
id	tenant_idcontentcontent_hashsurprise_scorememory_tieraccess_countlast_accessed
created_at	vector_idNc                    || _         || _        || _        || _        || _        || _        || _        || _        |	| _        |
| _	        y Nr   )selfr   r   r   r   r   r   r   r   r    r!   s              '/mnt/e/genesis-system/core/rlm/decay.py__init__z_MemoryRow.__init__9   sO     "(,&(*$"    r#   )r   intr   r   r   strr   r)   r   floatr   r)   r   r(   r   r   r    r   r!   Optional[str])__name__
__module____qualname____doc__	__slots__r&    r'   r%   r   r   ,   sz    I" $(## # 	#
 # # # #  # # !#r'   r   c                f    t        j                  | j                  d            j                         S )z;SHA-256 hash of content for dedup and similarity detection.zutf-8)hashlibsha256encode	hexdigest)r   s    r%   _content_hashr7   R   s#    >>'..12<<>>r'   
aggressivemoderateconservativeinfiniteDict[str, str]TIER_POLICY_MAPc                  V   e Zd ZdZeZ	 	 	 	 d	 	 	 	 	 	 	 ddZddZddZedd       Z		 	 	 d	 	 	 	 	 	 	 ddZ
ddZdd	Z	 	 d	 	 	 	 	 dd
Zd dZd!dZ	 	 	 	 	 	 d"dZd#dZ	 d$	 	 	 d%dZ	 d$	 	 	 d&dZ	 d$	 	 	 d&dZ	 	 	 	 	 	 d'dZ	 	 	 	 	 	 	 	 d(dZ	 d$	 	 	 	 	 	 	 d)dZed*d       Zy)+DecaySchedulerah  Manages memory decay cycles per tenant.

    Implements DecaySchedulerProtocol from contracts.py.

    Usage:
        scheduler = DecayScheduler(pg_dsn="postgresql://...", redis_url="redis://...")
        await scheduler.initialize()
        result = await scheduler.run_decay_cycle()
        print(result)  # {"deleted": 5, "demoted": 12, "retained": 83}
    Nc                   |xs  t         j                  j                  dd      | _        |xs  t         j                  j                  dd      | _        |xs  t         j                  j                  dd      | _        |xs  t         j                  j                  dd      | _        d| _        d| _        d| _	        d| _
        i | _        i | _        y)a  Initialize DecayScheduler.

        Args:
            pg_dsn: PostgreSQL connection DSN. Falls back to DATABASE_URL env.
            redis_url: Redis connection URL. Falls back to REDIS_URL env.
            qdrant_url: Qdrant URL for vector cleanup. Falls back to QDRANT_URL env.
            qdrant_api_key: Qdrant API key. Falls back to QDRANT_API_KEY env.

        Raises:
            ValueError: If pg_dsn cannot be resolved.
        DATABASE_URL 	REDIS_URL
QDRANT_URLQDRANT_API_KEYNF)osenvironget_pg_dsn
_redis_url_qdrant_url_qdrant_api_key_pg_pool_redis_qdrant_initialized_access_buffer_access_timestamps)r$   pg_dsn	redis_url
qdrant_urlqdrant_api_keys        r%   r&   zDecayScheduler.__init__v   s    $ C!C#Frzz~~k2'F%Ib)I-U@PRT1U " "' /179r'   c                  K   | j                   st        d      	 ddlm}  || j                   ddd      | _        | j                  r)	 dd	l	m
} |j                  | j                  d
      | _        | j                  r.	 ddlm}  || j                  | j"                  xs d	      | _        d| _        t        j)                  d| j                  d	u| j                  d	u| j$                  d	u       y	# t
        $ r t        j                  d       d	| _        Y w xY w# t
        t        f$ r'}t        j                  d|       d	| _        Y d	}~d	}~ww xY w# t
        t        f$ r'}t        j                  d|       d	| _        Y d	}~d	}~ww xY ww)z|Lazy-init backend connections.

        Raises:
            ValueError: If required connection strings are missing.
        zkDecayScheduler requires a PostgreSQL DSN. Provide pg_dsn argument or set DATABASE_URL environment variable.r   )create_async_engine      T)	pool_sizemax_overflowpool_pre_pingz,sqlalchemy not available; using mock PG poolN)decode_responseszRedis not available: %s)QdrantClient)urlapi_keyzQdrant not available: %sz7DecayScheduler initialized (PG=%s, Redis=%s, Qdrant=%s))rI   
ValueErrorsqlalchemy.ext.asynciorX   rM   ImportErrorloggerwarningrJ   redis.asyncioasynciofrom_urlrN   	ExceptionrK   qdrant_clientr_   rL   rO   rP   info)r$   rX   aioredisexcr_   s        r%   
initializezDecayScheduler.initialize   sj     ||T 

	!B/"	DM ??#0&//OOd 0  $6+(( 008D  !M]]$.[[,\\-	/5  	!NNIJ DM	!  + #8#>"#  + $93?#$s|   F!C/ F	(D 1F>-E +AF/%DFDFE)EFEFF	"F?FF		Fc                D  K   | j                   *	 | j                   j                          d{    d| _         | j                  *	 | j                  j	                          d{    d| _        d| _        d| _        y7 P# t        $ r Y Yw xY w7 +# t        $ r Y 4w xY ww)z)Gracefully close all backend connections.NF)rM   disposerj   rN   closerO   rP   r$   s    r%   rr   zDecayScheduler.close   s     ==$mm++--- !DM;;"kk''))) DK! .  * sm   B B  A>B  B B #B$B (B >B   	B	B BB B 	BB BB c                    | j                   S )z%Whether initialize() has been called.)rP   rs   s    r%   is_initializedzDecayScheduler.is_initialized   s        r'   c                4  K   | j                  |       d{   }|sddddS t        j                  t        j                        }d}d}d}g }	g }
|D ]  }|xs | j                  |j                        }|j                  }|j                   |j                  t        j                        }||z
  j                         dz  }t        ||j                  |j                  |      }|dk(  r!|dz  }|	j                  |j                         |d	k(  r>|dz  }| j!                  |j"                        }|
j                  |j                  |f       |dz  } |s| j%                  |	|
       d{    |||d}t&        j)                  d
||       |S 7 |7 &w)a  Run decay for one tenant or all tenants if tenant_id is None.

        Algorithm:
          1. Fetch all memories where last_accessed < threshold
          2. Calculate retention: R = e^(-t/S) where S = f(access_count, surprise_score)
          3. If R < retention_floor and access_count < 3 -> DELETE (forgotten)
          4. If R < 0.5 -> demote tier (semantic -> episodic -> working)
          5. If R >= 0.5 -> retain as-is

        Args:
            tenant_id: Process specific tenant only, or None for all.
            dry_run: If True, calculate but do not apply changes.
            policy_override: Override the tenant's decay policy. Useful for testing.

        Returns:
            {"deleted": N, "demoted": N, "retained": N}
        Nr   )deleteddemotedretainedtzinfo      @)hours_since_accessr   r   policydeleter   demotez%Decay cycle complete (dry_run=%s): %s)_fetch_decay_candidatesr   nowr   utc_resolve_policyr   r   r{   replacetotal_secondsr   r   r   appendr   _demote_tierr   _apply_decay_actionsre   rl   )r$   r   dry_runpolicy_overridememoriesr   rw   rx   ry   
delete_idsdemote_entriesmemr~   last_accesshours_elapsedactionnew_tierresults                     r%   run_decay_cyclezDecayScheduler.run_decay_cycle   s    . 55i@@ QA>>ll8<<( "
&( 	C$K(<(<S]](KF ++K!!))111F ;.==?&HM!#0 --"11	F !1!!#&&)8#1,,S__=%%svvx&89A3	6 ++JGGG$hO;WfMY AP Hs"   FFEF/F0$FFc                L    | j                   j                  t        |      d      S )zResolve decay policy for a tenant.

        In production this queries the EntitlementLedger. For now we use
        a configurable mapping that can be set via set_tenant_policy().
        Falls back to 'moderate'.
        r9   )_tenant_policiesrH   r)   r$   r   s     r%   r   zDecayScheduler._resolve_policy/  s!     $$((YDDr'   c           	         |t         vr,t        d|dt        t        j                                      t	        | d      si | _        || j
                  t        |      <   y)zSet the decay policy for a specific tenant.

        Args:
            tenant_id: Tenant UUID.
            policy: One of "aggressive", "moderate", "conservative", "infinite".

        Raises:
            ValueError: If policy is not recognized.
        zUnknown decay policy: 	. Valid: r   N)r   rb   listkeyshasattrr   r)   )r$   r   r~   s      r%   set_tenant_policyz DecayScheduler.set_tenant_policy8  sg     '(
 3~224568  t/046D!06c)n-r'   c           
       K   | j                  |       d{   }|sdddS i }|D ]2  }|j                  dd }|j                  |g       j                  |       4 d}d}g }	|j	                         D ]  \  }}
t        |
      dk  ri }|
D ]8  }t        |j                        }|j                  |g       j                  |       : |j	                         D ]  \  }}t        |      dk  rt        |d       }|D cg c]  }|j                  |j                  k7  s|  }}t        d |D              }|	j                  |j                  ||D cg c]  }|j                   c}d	       |d
z  }|t        |      z  }  |s,|	D ]'  }| j                  |d   |d   |d   	       d{    ) ||d}t        j                  d||       |S 7 c c}w c c}w 7 1w)a<  Nightly REM cycle: summarize, merge, prune.

        1. Find memories with overlapping content hashes (near-duplicates)
           -- uses first 8 chars of SHA-256 hash as similarity bucket
        2. Merge into single consolidated memory (keep highest surprise score)
        3. Update vector embedding for merged memory
        4. Delete source memories

        Args:
            tenant_id: Process specific tenant only, or None for all.
            dry_run: If True, calculate but do not apply changes.

        Returns:
            {"merged": N, "pruned": N}
        Nr   )mergedpruned   rZ   c                    | j                   S r#   )r   )ms    r%   <lambda>z6DecayScheduler.run_rem_consolidation.<locals>.<lambda>  s    a6F6F r'   )keyc              3  4   K   | ]  }|j                     y wr#   )r   ).0r   s     r%   	<genexpr>z7DecayScheduler.run_rem_consolidation.<locals>.<genexpr>  s     "Ca1>>"Cs   )survivor_idtotal_access_countr   r   r   r   r   z+REM consolidation complete (dry_run=%s): %s)_fetch_all_memoriesr   
setdefaultr   itemslenr)   r   maxr   sum_apply_mergere   rl   )r$   r   r   r   bucketsr   prefixr   r   	merge_opsgrouptenant_groupsr   t_idt_groupsurvivorr   	to_deletetotal_accessopr   s                        r%   run_rem_consolidationz$DecayScheduler.run_rem_consolidationO  s    ( 11)<<1-- 02 	7C%%bq)Fvr*11#6	7 *,	$]]_ 	)MFE5zA~ :<M >#--(((b188=> "/!4!4!6 )gw<!# w,FG(/G11448;;3FQG	G  #"C7"CC  #+;;*61:";A144";" 
 !#i.(#)	):  '' "= 1')*>'?!,/ (    #f5A7FSk =< H #<sA   GGC&G>GG!/GG#AG+G,%GGc                    dddS )zReturn cron expressions for decay and REM jobs.

        Returns:
            Dict mapping job name to cron expression string.
        z	0 3 * * *z	0 2 * * 0decay_cyclerem_consolidationr1   rs   s    r%   get_cron_schedulez DecayScheduler.get_cron_schedule  s     '!,
 	
r'   c           	        K   | j                   | j                  d}|j                  |      }|(t        d|dt	        |j                                       |        d{   S 7 w)a  Entry point for cron runner.

        Args:
            job_name: One of "decay_cycle", "rem_consolidation".

        Returns:
            Result dict from the corresponding method.

        Raises:
            ValueError: If job_name is not recognized.
        r   NzUnknown scheduled job: r   )r   r   rH   rb   r   r   )r$   job_namedispatchhandlers       r%   run_scheduledzDecayScheduler.run_scheduled  ss       //!%!;!;
 ,,x(?)( 6x}}/02  Ys   AA(!A&"A(c                  K   | d| }t        j                  t        j                        }| j                  _	 d| }| j                  j                  |       d{    | j                  j                  d| |j                                d{    y| j                  j                  |d      dz   | j                  |<   || j                  |<   y7 v7 C# t        $ r }t        j                  d|       Y d}~dd}~ww xY ww)a  Record that a memory was accessed (read/search hit).

        Updates: last_accessed timestamp, access_count += 1.
        This strengthens the memory against decay.

        Uses Redis INCR for fast counting, flushed to PG periodically.
        If Redis is not available, falls back to direct PG update.

        Non-existent memory_id is silently ignored.

        Args:
            tenant_id: Tenant UUID.
            memory_id: Memory ID (string representation of PG id).
        :Ndecay:access:decay:last_access:z Redis access tracking failed: %sr   r   )r   r   r   r   rN   incrset	isoformatrj   re   rf   rQ   rH   rR   )r$   r   	memory_id
buffer_keyr   	redis_keyrn   s          r%   record_accesszDecayScheduler.record_access  s     " "{!I;/
ll8<<(;;"	H+J<8	kk&&y111kkoo(5MMO    ##J2Q6 	J' /2
+ 2
  HA3GGHsR   7D#C C4C CC =DC C 	D!C<7D<DDc                j  K   d}| j                   9	 g }| j                   j                  d      2 3 d{   }|j                  |       t        | j                  j                               D ]y  \  }}|j                  dd      }t        |      d	k7  r'|\  }	}
| j                   j                  |      }| j                  |
||r|j#                         nd
       d{    |dz  }{ | j                  j%                          | j                   j%                          |S 7 6 |D ]  }| j                   j                  |       d{  7  }|*|j	                  dd      }d| }| j                   j                  |       d{  7  }|j                  dd      }t        |      d	k7  r|\  }	}
| j                  |
t        |      |
       d{  7   | j                   j                  ||       d{  7   |dz  } # t        $ r!}t        j                  d|       Y d}~d}~ww xY w7 Sw)znFlush buffered access counts to PostgreSQL.

        Returns:
            Number of memories updated.
        r   Nzdecay:access:*r   rB   r   r   r   rZ   )r   count_incrementr   zRedis flush failed: %s)rN   	scan_iterr   rH   r   splitr   _update_access_in_pgr(   r   rj   re   rf   r   rQ   r   rR   r   clear)r$   updatesr   r   countr   ts_key	timestamppartstenant_id_strr   rn   tss                r%   flush_access_bufferz"DecayScheduler.flush_access_buffer  s/      ;;">!%!6!67G!H % %#KK$8 "&d&9&9&?&?&A!B 	J$$S!,E5zQ',$M9((,,Z8B++# %02blln ,   
 qLG	 	!!#%%'Y%!H   !C"&++//#"666E} !$_b!AJ1*>F&*kkoof&= = =I&,,S!4E5zQ /4,M933"+(+E
&/ 4    ++,,S&999qLG+!,  >7==>s   H3H D!DD!H 
BH3H0AH3D!!$H E=H FAH G$H 4G75H H3	H-H("H3(H--H3c                  K   | j                  |       d{   }|sdddi dS t        j                  t        j                        }d}i }|D ]  }|j
                  }|j                   |j                  t        j                        }||z
  j                         dz  }t        ||j                  |j                        }	||	z  }|j                  }
|j                  |
d      dz   ||
<    t        |      }|d|dkD  r||z  |dS d|dS 7 w)	zGet decay statistics.

        Args:
            tenant_id: Filter to specific tenant, or None for global stats.

        Returns:
            Dict with keys: total_memories, total_decayed, avg_retention, etc.
        Nr   g        )total_memoriestotal_decayedavg_retentionby_tierrz   r|   )r}   r   r   r   )r   r   r   r   r   r   r{   r   r   r   r   r   r   rH   r   )r$   r   r   r   total_retentionr   r   r   hoursrtiertotals               r%   get_decay_statszDecayScheduler.get_decay_stats)  s9     11)<<"#!"!$	  ll8<<("$ 	5C++K!!))111F;&557&@E##( --"11A
 q O??D#KKa014GDM	5  H#8=	_u4	
 	
 HK	
 	
= =s   DDC4Dc                  K   t        | d      r/| j                  }||D cg c]  }|j                  |k(  s| }}|S | j                  g S 	 ddlm} | j                  j                         4 d{   } |d      }|j                  |d|rt        |      ndi       d{   }|j                         }|D 	cg c]Y  }	t        |	d   t        t        |	d               |	d   |	d	   t        |	d
         |	d   t        |	d         |	d   |	d   |	d   
      [ c}	cddd      d{    S c c}w 7 7 c c}	w 7 # 1 d{  7  sw Y   yxY w# t        $ r"}
t        j!                  d|
       g cY d}
~
S d}
~
ww xY ww)zFetch memories eligible for decay evaluation.

        In production, this queries PostgreSQL. For testability, this
        method can be overridden or the internal _memories list can be
        pre-populated.
        _test_memoriesNr   textaj  
                    SELECT id, tenant_id, content, content_hash,
                           surprise_score, memory_tier, access_count,
                           last_accessed, created_at, vector_id
                    FROM rlm_memories
                    WHERE (:tid IS NULL OR tenant_id = :tid)
                    ORDER BY last_accessed ASC
                tidr   rZ         rY         r   	   r   z$Failed to fetch decay candidates: %s)r   r   r   rM   
sqlalchemyr   connectexecuter)   fetchallr   r   r*   r(   rj   re   error)r$   r   r   r   r   connsqlr   rowsrowrn   s              r%   r   z&DecayScheduler._fetch_decay_candidates]  s     4)***H$'/L!1;;)3KALLO== I 	'}},,.  $    $||%9Y$G   (  $  q6"&s3q6{"3 #A%(V',SV}$'F%(Q[&)!f#&q6"%a&   M   8  	LL?EI	s   F D-D-F $E 1D22E 5-D="D4#D=;AD6D=E 'D;(E ,F 2E 4D=6D=;E =EEEE F E 	E=E82E=3F 8E==F c                @   K   | j                  |       d{   S 7 w)z2Fetch all memories for stats or REM consolidation.N)r   r   s     r%   r   z"DecayScheduler._fetch_all_memories  s      11)<<<<s   c                  K   t        | d      rb| j                  D cg c]  }|j                  |vs| c}| _        |D ].  \  }}| j                  D ]  }|j                  |k(  s||_         . 0 y| j                  y	 ddlm} | j                  j                         4 d{   }|r"|j                   |d      d|i       d{    |D ](  \  }}|j                   |d      ||d       d{    * ddd      d{    yc c}w 7 k7 I7  7 # 1 d{  7  sw Y   yxY w# t        $ r }t        j                  d	|       Y d}~yd}~ww xY ww)
zApply decay deletions and demotions to backends.

        Args:
            delete_ids: Memory IDs to delete from PG + Qdrant.
            demote_entries: List of (id, new_tier) tuples to update.
        r   Nr   r   -DELETE FROM rlm_memories WHERE id = ANY(:ids)idsz:UPDATE rlm_memories SET memory_tier = :tier WHERE id = :id)r   r   z!Failed to apply decay actions: %s)r   r   r   r   rM   r   r   beginr   rj   re   r   )	r$   r   r   r   mem_idr   r   r   rn   s	            r%   r   z#DecayScheduler._apply_decay_actions  sz     4)*..#!$$j2H#D %3  ,, Attv~(0
 == 	C'}}**, 
 
,,LM
+   )7 $FH,,YZ!)8  
 
 
#


 
 
 
  	CLL<cBB	Cs   ED
D
.E$E?$D, #D$D, ' DD*D2D3D9D, DD, 	ED, DDD, D)D D)%D, (E)D, ,	E5EEEEc                  K   t        | d      rf| j                  D ]  }|j                  |k(  s||_         n | j                  D cg c]!  }|j                  |k(  s|j                  |vr|# c}| _        y| j                  y	 ddlm} | j                  j                         4 d{   }|j                   |d      ||d       d{    |r"|j                   |d      d|i       d{    ddd      d{    yc c}w 7 a7 @7 7 # 1 d{  7  sw Y   yxY w# t        $ r }t        j                  d	|       Y d}~yd}~ww xY ww)
zApply a REM merge operation.

        Args:
            survivor_id: The memory ID that survives.
            total_access_count: Summed access_count from all merged memories.
            delete_ids: IDs of source memories to delete.
        r   Nr   r   z
                        UPDATE rlm_memories
                        SET access_count = :cnt
                        WHERE id = :sid
                    )cntsidr  r  zFailed to apply merge: %s)r   r   r   r   rM   r   r   r  r   rj   re   r   )r$   r   r   r   r   r   r   rn   s           r%   r   zDecayScheduler._apply_merge  se     4)*(( 44;&%7AN
  ..#44;&!$$j*@ #D == 	;'}}**,  ll  
 /{C   ,,LM
+    #     	;LL4c::	;s   +EE&D,E$D& 'D	(D& +D
D#D.D/D3D& >D?D& E	D& DDD& D#DD#D& "E#D& &	E/E
E
EEc           	       K   | j                   y	 ddlm} |xs1 t        j                  t
        j                        j                         }| j                   j                         4 d{   }|j                   |d      ||t        |      d       d{    ddd      d{    y7 B7 7 	# 1 d{  7  sw Y   yxY w# t        t        f$ r!}t        j                  d||       Y d}~yd}~ww xY ww)zoUpdate access_count and last_accessed in PostgreSQL.

        Silently ignores non-existent memory_id.
        Nr   r   z
                        UPDATE rlm_memories
                        SET access_count = access_count + :inc,
                            last_accessed = :ts
                        WHERE id = :mid
                    )incr   midz Access update skipped for %s: %s)rM   r   r   r   r   r   r   r   r  r   r(   rb   rj   re   debug)r$   r   r   r   r   r   r   rn   s           r%   r   z#DecayScheduler._update_access_in_pg  s      == 	M'H(,,x||"<"F"F"HB}}**, 	 	ll   ,2c)nM  	 	 		 	 	 	 I& 	MLL;YLL	Ms   C;AC *B-+C .)B3B/B3C 'B1(C ,C;-C /B31C 3C9B<:CC C;C C8C3.C;3C88C;c                   t         j                  j                  t         j                  j                  t         j                  j                  t         j                  j                  t         j                  j                  t         j                  j                  t         j
                  j                  t         j
                  j                  i}|j                  | t         j                  j                        S )ziDemote a memory tier one level down.

        semantic -> episodic -> working -> working (floor)
        )r   SEMANTICvalueEPISODICWORKINGDISCARDrH   )current_tierdemotion_maps     r%   r   zDecayScheduler._demote_tier  s     %%z':':'@'@%%z'9'9'?'?$$j&8&8&>&>$$j&8&8&>&>	
 j.@.@.F.FGGr'   )NNNN)rS   r+   rT   r+   rU   r+   rV   r+   )returnNone)r  bool)NFN)r   Optional[UUID]r   r  r   r+   r  Dict[str, int])r   r   r  r)   )r   r   r~   r)   r  r  )NF)r   r  r   r  r  r  )r  r<   )r   r)   r  Dict[str, Any])r   r   r   r)   r  r  )r  r(   r#   )r   r  r  r  )r   r  r  zList[_MemoryRow])r   	List[int]r   zList[tuple]r  r  )r   r(   r   r(   r   r  r  r  )r   r)   r   r(   r   r+   r  r  )r  r)   r  r)   )r,   r-   r.   r/   r   r&   ro   rr   propertyru   r   r   r   r   r   r   r   r   r   r   r   r   r   r   staticmethodr   r1   r'   r%   r?   r?   g   s   	 $N !%#'$((,:: !: "	:
 &:B1/f"& ! ! %))-	C!C C '	C
 
CRE72 %)I!I I 
	I^	
8$2$2*-$2	$2L8~ +/.
'.
	.
j +/4'4	4n +/='=	=(C(C $(C 
	(CT-;-;  -; 	-;
 
-;f (,	MM M %	M
 
M< H Hr'   r?   )r   r)   r  r)   )&r/   
__future__r   r3   loggingrF   r   r   r   typingr   r   r	   r
   uuidr   	contractsr   r   r   r   decay_curvesr   r   r   r   	getLoggerre   r   r7   STARTERr  PROFESSIONAL
ENTERPRISEQUEENr=   __annotations__r?   r1   r'   r%   <module>r*     s    #   	 2 2 , ,    
		+	,## ##L? ##Z!!>j	# u
H u
Hr'   