Ë
    7¨jâ+  ã            	      ó>  — d Z ddlmZ ddlZddlmZ ddlZddlmZ ddl	m
Z
mZ ddlmZ d	Zd
ZdZddddœZddddœZdZdddidddg d¢dœdg d¢dœddiddidœg d¢ddœdœddidddidœdœg d¢ddœZ G d „ d!e«      Zd*d"„Zd+d#„Zd,d$„Zd-d%„Zd.d&„Zd/d'„Zd0d(„Zd1d)„Zy)2uÎ  Claude reviews of a draft forecast, informed by the current guidance and by
similar past forecasts. Claude advises; it never sets or dictates a rating.

Request layout (prompt-cache friendly â€” stable content first):
  system[0]  frozen reviewer instructions            (never changes)
  system[1]  guidance + center config for this run   (stable per config version) <- cache breakpoint
  messages   the draft, analogs, and the task         (varies every call)
é    )ÚannotationsN)ÚDecimalé   )ÚASPECTS)ÚAFP_PROBLEM_NAMESÚLIKELIHOOD_NAMES)Úget_settingsz2026-09-14.1zserver-side-fallback-2026-07-01i }  )g      @g      9@g      @g      à?)g      $@g      I@g      )@g      Ð?)úclaude-opus-5zclaude-fable-5-1zclaude-opus-4-8zìReview this draft for clarity and internal consistency: do the bottom line, danger ratings, avalanche problems and travel advice agree with each other and with the guidance? Flag jargon, passive voice, and missing what/where/what-to-do.a	  Write a suggested Bottom Line for this draft (three sentences or fewer; what is it, where is it, what can readers do) from the structured problems and ratings, following the writing guidance. Also note anything in the draft that makes the bottom line hard to write.u&  Sanity-check the draft's danger ratings against its problems (likelihood, size, location), the CMAH hazard-chart suggestion, the on-the-line guidance, and the similar past forecasts. Where a rating looks high or low, explain why and what to double-check â€” never state which rating is correct.)Úreview_draftÚdraft_bottom_lineÚsanity_checku„  You are an experienced avalanche forecaster and editor reviewing a public avalanche forecast before it is published.

Ground rules:
- The forecaster decides. You advise. Never state what a danger rating must be, and never present your view as the correct rating.
- The current guidance supplied below (USDA FS Avalanche Forecast Guidance, the Conceptual Model of Avalanche Hazard, and the center's problem descriptions) is the standard. Past forecasts are shown only as context: many were written under older conventions (for example "Normal Caution" or different problem choices) and may not follow current guidance â€” do not treat them as correct just because they were published.
- Be concise and practical. Cite the guidance section when it supports a point (e.g. "FG Â§3.3", "FG Table 1").
- Do not rewrite the whole forecast.
- Respond only with the JSON object described by the output schema.ÚobjectÚtypeÚstringÚarray)ÚinfoÚ
suggestionÚ	important)r   Úenum)Úbottom_lineÚdangerÚproblemsÚtravel_adviceÚ
discussionÚgeneral)ÚseverityÚsectionÚtextÚguidance_refF)r   Ú
propertiesÚrequiredÚadditionalProperties)r   Úitems)ÚsummaryÚissuesÚsuggested_bottom_lineÚquestions_for_forecasterc                  ó   — e Zd Zy)ÚAIUnavailableN)Ú__name__Ú
__module__Ú__qualname__© ó    ú0/var/www/avy-guidance/api/app/services/claude.pyr)   r)   I   s   „ Ør.   r)   c                 ó<   — t        t        «       j                  «      S )N)Úboolr	   Úanthropic_api_keyr-   r.   r/   Úenabledr3   M   s   € Ü”“×0Ñ0Ó1Ð1r.   c                óº  — d|› �ddg}| d   D ]›  }|j                  d|d   › �«       |j                  |d   «       dD ]@  \  }}|j                  |«      sŒ|j                  |› d	�d
j                  ||   «      z   «       ŒB |j                  d«      sŒ…|j                  d|d   › �«       Œ� |ddgz  }| d   D ]Q  }|d   sŒ	|j                  d|d   › d
|d   › d	|d   › d|j                  dd«      › d|j                  dd«      › �
«       ŒS |ddgz  }|| d   D �cg c]  }d|d   › d	|d   › �‘Œ c}z  }|ddgz  }| d   j                  «       D ]+  \  }}	|j                  |› d	�d
j                  |	«      z   «       Œ- |dddt	        j
                  | d   d¬ «      d!t	        j
                  | j                  d"i «      d¬ «      › �gz  }d#j                  |«      S c c}w )$z;Stable per config version: the guidance the review applies.z# Guidance for Ú z<## Avalanche problem types (FG Table 1; center descriptions)ÚproblemTypesz### ÚnameÚdesc))Ú
InitiationÚ
initiation)zTermination/transitionÚtermination)ÚConsiderationsÚconsiderationsú: ú ÚsaczCenter notes: u#   ## Danger levels (NAPADS, FG Â§2.1)ÚdangerLevelsÚlevelz- Úadvicez Likelihood: Ú
likelihoodz Size/distribution: ÚsizeDistu0   ## On-the-line and special situations (FG Â§2.2)Ú	onTheLineÚtitler   u   ## Writing guidance (FG Â§3)ÚwritingzM## CMAH hazard-chart danger table used by the tool (a suggestion, not a rule)zcRows likelihood 1-5 (Unlikely..Certain); columns D1, D2, D3, D4-5; values 0-5 (No Rating..Extreme):ÚdangerTableT)Ú	sort_keyszBand labels: Ú
bandLabelsú
)ÚappendÚgetÚjoinr#   ÚjsonÚdumps)
ÚconfigÚcenter_nameÚlinesÚpÚlabelÚkeyÚdÚtr   r#   s
             r/   Úguidance_contextrZ   Q   s[  € à˜{˜mÐ,¨bÐ2pÐq€EØ�NÑ#ò 6ˆØ�‰�t˜A˜f™I˜;Ð'Ô(Ø�‰�Q�v‘YÔð Jò 	>‰JˆE�3Ø�u‰u�S�zØ—‘ ˜w b˜\¨C¯H©H°Q°s±VÓ,<Ñ<Õ=ð	>ð �5‰5��<Ø�L‰L˜>¨!¨E©(¨Ð4Õ5ð6ð 
ˆbÐ7Ð8Ñ8€EØ�NÑ#ò XˆØˆW‹:Ø�L‰L˜2˜a ™j˜\¨¨1¨V©9¨+°R¸¸(¹°}ÀMÐRS×RWÑRWÐXdÐfhÓRiÐQjÐj~ð  @A÷  @Eñ  @Eð  FPð  RTó  @Uð  Vð  Wõ  XðXð 
ˆbÐDÐEÑE€EØ	°f¸[Ñ6IÖJ°��1�W‘:�,˜b  6¡ Ò,ÒJÑJ€EØ	ˆbÐ0Ð1Ñ1€EØ  Ñ+×1Ñ1Ó3ò 7‰ˆ�Ø�‰˜�y �^ c§h¡h¨u£oÑ5Õ6ð7à	ˆbÐaØsÜ�j‰j˜ Ñ.¸$Ô?ØœdŸj™j¨¯©°LÀ"Ó)EÐQUÔVÐWÐXðZñ Z€Eð �9‰9�UÓÐùò Ks   ÄGc                ó   ‡— i }| D ]6  }|j                  «       \  }}|j                  |g «      j                  |«       Œ8 t        t        «      D ��ci c]  \  }}||“Œ
 c}}Šdj                  ˆfd„|j                  «       D «       «      S c c}}w )Nz; c           	   3  óz   •K  — | ]2  \  }}|› d dj                  t        |‰j                  ¬«      «      › �–— Œ4 y­w)r>   z, )rW   N)rO   ÚsortedrN   )Ú.0ÚbÚvÚorders      €r/   ú	<genexpr>z_loc_summary.<locals>.<genexpr>r   s5   øè ø€ Ò_ÁtÀqÈ!˜�s˜"˜TŸY™Y¤v¨a°U·Y±YÔ'?Ó@ÐAÔBÑ_ùs   ƒ8;)ÚsplitÚ
setdefaultrM   Ú	enumerater   rO   r#   )Ú	locationsÚby_bandÚlocÚaspectÚbandÚiÚara   s          @r/   Ú_loc_summaryrm   l   s€   ø€ Ø$&€GØò 4ˆØ—y‘y“{‰ˆ�Ø×Ñ˜4 Ó$×+Ñ+¨FÕ3ð4ô (¬Ó0×1‘d�a˜ˆQ�‰TÓ1€EØ�9‰9Ó_ÈwÏ}É}ËÔ_Ó_Ð_ùó 2s   ÁB
c                ó„  — |d   D �ci c]  }|d   |d   “Œ }}g }t        | d   d   «      D ]p  \  }}| d   d   |   }|j                  |dz   t        j                  |d   «      t	        j                  |d	   «      |d
   d   |d
   d   gt        |d   «      dœ«       Œr d }| j                  d«      �%dD �	ci c]  }	|	|j                  | d|	› �   «      “Œ }}	t        | d   «      | j                  d«      | d   j                  dg «      ||xs ddD �	ci c]  }	|	|j                  | d   d   |	   «      “Œ c}	| j                  d«      xs i | d   j                  d| d   j                  dg «      «      D �cg c]  }|d   ‘Œ	 c}| j                  d«      xs d| j                  d«      xs ddœ
S c c}w c c}	w c c}	w c c}w )NrA   rB   r7   Úinputsr   Úcomputedé   r   rD   ÚsizeÚminÚmaxrf   )Úrankr   rD   Ú
size_rangeÚwhereÚfinal_upper©ÚupperÚmiddleÚlowerÚfinal_Ú
valid_dateÚ	zone_nameÚ
conditionsznot yet setÚsuggestionsÚjustificationsÚfinalChecksÚchecksr   r   r5   Únotes)
r~   ÚzoneÚobserved_conditionsr   Úforecaster_dangerÚtool_suggestionÚpairing_justificationsÚguidance_checksr   r…   )re   rM   r   rN   r   rm   Ústr)
ÚrunrR   rX   Únamesr   rk   rU   ÚcÚfinalr_   s
             r/   Údraft_payloadr‘   u   só  € Ø,2°>Ñ,BÖC qˆQˆw‰Z˜˜6™Ñ"ÐC€EÐCØ€HÜ˜#˜h™-¨
Ñ3Ó4ò ‰ˆˆ1Ø�
‰O˜JÑ'¨Ñ*ˆØ�‰Ø˜‘EÜ%×)Ñ)¨!¨F©)Ó4Ü*×.Ñ.¨q°©Ó?Ø˜V™9 UÑ+¨Q¨v©Y°uÑ-=Ð>Ü! ! K¡.Ó1ñ
õ 	ðð €EØ
‡w�wˆ}ÓÐ)Ø:VÖW°Q��E—I‘I˜c F¨1¨# ,Ñ/Ó0Ñ0ÐWˆÐWä˜#˜lÑ+Ó,Ø—‘˜Ó$Ø" 8™}×0Ñ0°¸rÓBØØ"Ò3 mØUqÖrÐPQ˜A˜uŸy™y¨¨Z©¸Ñ)GÈÑ)JÓKÑKÒrØ"%§'¡'Ð*:Ó";Ò"A¸rØ/2°:©×/BÑ/BÀ=ÐRUÐV`ÑRa×ReÑReÐfnÐprÓRsÓ/tÖu¨!˜A˜f›IÒuØ—w‘w˜}Ó-Ò3°Ø—‘˜Ó!Ò' Rñð ùò Dùò Xùò sùâus   ˆF.Â7F3Ä"F8Å5F=c                ó®  — |d   D �ci c]  }|d   |d   “Œ }}| D ���cg c]—  }t        |d   «      |d   dD �ci c]  }||j                  |d|› �   «      “Œ c}|d   D �cg c]7  }t        j                  |d	   «      t        j                  |d
   «      |d   dœ‘Œ9 c}|j                  d«      xs dd d dœ‘Œ™ c}}}S c c}w c c}w c c}w c c}}}w )NrA   rB   r7   r~   Úguidance_erary   Údanger_r   r   rD   Úsize_max)r   rD   r•   r   r5   i�  )ÚdateÚerar   r   r   )rŒ   rN   r   r   )ÚanalogsrR   rX   rŽ   rl   r_   rU   s          r/   Úanalog_payloadr™   ’   s  € Ø,2°>Ñ,BÖC qˆQˆw‰Z˜˜6™Ñ"ÐC€EÐCð ÷ð ð ô ˜˜,™Ó(Ø�^Ñ$Ø?[Ö\¸!�q˜%Ÿ)™) A¨°¨s mÑ$4Ó5Ñ5Ò\ð ˜:™öð ô +×.Ñ.¨q°©yÓ9ÔIY×I]ÑI]Ð^_Ð`lÑ^mÓInØ˜z™]ó,òð
 ŸE™E -Ó0Ò6°B¸¸Ð=ó
	
ôð ùò Dùò
 ]ùòùôs'   ˆC CºCÁ	CÁ"<CÂCÃ
Cc                ór  — |t         vrt        d|› �«      ‚dt         |   › dt        j                  t	        | |«      dt
        ¬«      › dt        j                  t        ||«      dt
        ¬«      › d�}|t        t        gdd	t        d
œd	t        ||«      ddidœgd|dœgddt        dœidœ}|dk(  rddi|d<   |S )Nzunknown mode zTask: z

<draft_forecast>
rq   )ÚindentÚdefaultzw
</draft_forecast>

<similar_past_forecasts note="context only; legacy-era forecasts may not follow current guidance">
z
</similar_past_forecasts>rœ   r   ©r   r   r   Ú	ephemeral)r   r   Úcache_controlÚuser)ÚroleÚcontentÚformatÚjson_schema)r   Úschema)ÚmodelÚ
max_tokensÚbetasÚ	fallbacksÚsystemÚmessagesÚoutput_configr
   ÚadaptiveÚthinking)ÚMODESÚ
ValueErrorrP   rQ   r‘   rŒ   r™   Ú
MAX_TOKENSÚFALLBACK_BETAÚSYSTEMrZ   ÚOUTPUT_SCHEMA)r�   rR   rS   r˜   Úmoder¦   r    Úparamss           r/   Úbuild_requestr·   ¤   së   € Ø”5ÑÜ˜=¨¨Ð/Ó0Ð0à
”�t‘�ð Ü!ŸZ™Z¬°c¸6Ó(BÈ1ÔVYÔZÐ[ð \qä�:‰:”n W¨fÓ5¸aÌÔMÐ
NÐNið	kð 	ð Ü Ü�Øà¤VÑ,ØÔ%5°f¸kÓ%JÐ^dÐfqÐ]rÑsð
ð %°Ñ6Ð7Ø"¨]ÄmÑ$TÐUñ€Fð �ÒØ$ jÐ1ˆˆzÑØ€Mr.   c                ó.  — t         j                  | t         d   «      \  }}}}t        |dd«      xs d|z  t        |dd«      xs d|z  z   t        |dd«      xs d|z  z   t        |dd«      xs d|z  z   dz  }t        t	        t        |d«      «      «      S )	Nr
   Úinput_tokensr   Úoutput_tokensÚcache_creation_input_tokensÚcache_read_input_tokensi@B é   )ÚPRICESrN   Úgetattrr   rŒ   Úround)r¦   ÚusageÚp_inÚp_outÚp_cwÚp_crÚtotals          r/   Úcost_usdrÇ   À   s±   € Ü$Ÿj™j¨´°Ñ0GÓHÑ€Dˆ%��tä	�˜¨Ó	*Ò	/¨a°4Ñ7Ü�5˜/¨1Ó-Ò2°°eÑ
;ñ	<ä�5Ð7¸Ó;Ò@¸qÀDÑ
Hñ	Iô �5Ð3°QÓ7Ò<¸1ÀÑ
Dñ	Eð 	ñ€Eô ”3”u˜U A“Ó'Ó(Ð(r.   c           
     ó  — t        «       }|j                  st        d«      ‚t        j                  |j                  dd¬«      } |j
                  j                  j                  di | ¤Ž5 }|j                  «       }ddd«       j                  }|| d   k7  r|nd}|j                  }|j                  ||j                  |j                  t        |dd«      t        |dd«      t        ||«      ddd	œ	}|j                  d
k(  rd|d<   |S t!        d„ |j"                  D «       d«      }		 t%        j&                  |	«      |d<   |S # 1 sw Y   ŒÅxY w# t$        j(                  $ r! d|j                  › d�|d<   d|	dd i|d<   Y |S w xY w)zHCall Claude (streamed server-side) and return a result dict for storage.z3AI review is not configured (no ANTHROPIC_API_KEY).g     À‚@r   )Úapi_keyÚtimeoutÚmax_retriesNr¦   r¼   r»   )	Ústop_reasonÚfallback_modelr¹   rº   Úcache_read_tokensÚcache_write_tokensrÇ   ÚoutputÚerrorÚrefusalz The model declined this request.rÑ   c              3  óT   K  — | ]   }|j                   d k(  sŒ|j                  –— Œ" y­w)r   Nr�   )r^   r_   s     r/   rb   zrun_review.<locals>.<genexpr>å   s   è ø€ ÒE˜A°A·F±F¸fÓ4D�—•ÑEùs   ‚(—(r5   rÐ   z!Unreadable response (stop_reason=z).Úrawi   r-   )r	   r2   r)   Ú	anthropicÚ	AnthropicÚbetar«   ÚstreamÚget_final_messager¦   rÁ   rÌ   r¹   rº   r¿   rÇ   Únextr¢   rP   ÚloadsÚJSONDecodeError)
r¶   ÚsettingsÚclientrØ   ÚmessageÚ	served_byrÍ   rÁ   Úresultr   s
             r/   Ú
run_reviewrâ   Ë   s�  € ä‹~€HØ×%Ò%ÜÐQÓRÐRÜ× Ñ ¨×)CÑ)CÈUÐ`aÔb€FØ	$ˆ�‰×	Ñ	×	$Ñ	$Ñ	. vÑ	.ð -°&Ø×*Ñ*Ó,ˆ÷-ð —‘€IØ"+¨v°g©Ò">‘YÀD€NØ�M‰M€Eà×*Ñ*Ø(Ø×*Ñ*Ø×,Ñ,Ü$ UÐ,EÀtÓLÜ% eÐ-JÈDÓQÜ˜Y¨Ó.ØØñ
€Fð ×Ñ˜iÒ'Ø<ˆˆw‰ØˆÜÑE §¡ÔEÀrÓJ€Dð0ÜŸ:™: dÓ+ˆˆxÑð €M÷5-ð -ûô. ×Ñò 0Ø=¸g×>QÑ>QÐ=RÐRTÐUˆˆw‰Ø! 4¨¨ ;Ð/ˆˆxÒØ€Mð0ús   Á*D?Ä%E Ä?EÅ0E?Å>E?)Úreturnr1   )rR   ÚdictrS   rŒ   rã   rŒ   )rf   z	list[str]rã   rŒ   )r�   rä   rR   rä   rã   rä   )r˜   ú
list[dict]rR   rä   rã   rå   )r�   rä   rR   rä   rS   rŒ   r˜   rå   rµ   rŒ   r¦   rŒ   rã   rä   )r¦   rŒ   rã   r   )r¶   rä   rã   rä   )Ú__doc__Ú
__future__r   rP   Údecimalr   rÕ   Úenginer   Úmappingr   r   rÝ   r	   ÚPROMPT_VERSIONr²   r±   r¾   r¯   r³   r´   Ú	Exceptionr)   r3   rZ   rm   r‘   r™   r·   rÇ   râ   r-   r.   r/   ú<module>rí      s  ðñõ #ã Ý ã å ß 9Ý #à€Ø1€Ø€
ð -Ø0Ø.ñ
€ð Cð eð }ñ	€ð
G€ð à˜HÐ%àà à)1Ò;^Ñ _Ø(0ò  ;Jñ   KØ# XÐ.Ø%+¨XÐ$6ñ	ò LØ(-ñ
ñ
ð #)¨(Ð!3Ø-4ÀÈÐ?QÑ$Rñ#ò& [Ø!ñ-€ô4	�Iô 	ó2óó6`óó:ó$ó8)ô r.   