1111Requires PYTHONPATH including workspace src/ (see .vscode/settings.json).
1212
1313ROA Manifesto alignment: §3-4, §6
14+
15+ Canonical telemetry: ``samples/01_roa_agent/data/01_roa_agent.db`` (optional).
1416"""
1517from __future__ import annotations
1618
1719import json
1820import logging
1921import random
22+ import sys
2023from abc import ABC , abstractmethod
2124from datetime import datetime , timezone
2225from pathlib import Path
2326from typing import Any , Dict , List , Optional , Tuple , Union
2427
25- from dir_core import (
28+ _REPO_ROOT = Path (__file__ ).resolve ().parents [2 ]
29+ _SRC = _REPO_ROOT / "src"
30+ if str (_SRC ) not in sys .path :
31+ sys .path .insert (0 , str (_SRC ))
32+
33+ from dir_core import ( # noqa: E402
2634 AgentState ,
2735 DecisionRecord ,
2836 EscalationRequest ,
3341 SelfCheckResult ,
3442 new_dfid ,
3543)
44+ from dir_core .storage import AuditStore , ensure_db , sqlite_storage # noqa: E402
3645from dir_core .utils .logging_utils import log_with_dfid
3746
47+ from telemetry import ( # noqa: E402
48+ SIMULATION_ID ,
49+ record_roa_cycle_result ,
50+ record_simulation_end ,
51+ record_simulation_start ,
52+ )
53+
3854logging .basicConfig (level = logging .INFO , format = "%(levelname)s %(message)s" )
3955logger = logging .getLogger (__name__ )
4056
@@ -704,9 +720,9 @@ def formulate_policy(self, dfid: str, explain_result: ExplainResult) -> Policy:
704720# =============================================================================
705721
706722
707- def main ( ) -> None :
708- """Demonstrate full ROA lifecycle with dynamic agents and escalation scenarios ."""
709-
723+ def _run_roa_demo ( audit : AuditStore ) -> None :
724+ """Scenarios A–G: ROA lifecycle (one ``decision_audit`` row per ``run_decision_cycle``) ."""
725+
710726 print ("=" * 70 )
711727 print ("ROA Agent Sample - Full Lifecycle Demonstration" )
712728 print ("=" * 70 )
@@ -737,7 +753,8 @@ def main() -> None:
737753 }
738754
739755 result_a = btc_agent .run_decision_cycle (dfid_a , context_a )
740-
756+ record_roa_cycle_result (audit , dfid_a , SIMULATION_ID , result_a , scenario_label = "A" )
757+
741758 if isinstance (result_a , PolicyProposal ):
742759 print (f"\n [RESULT A] PolicyProposal emitted:" )
743760 print (f" DFID: { result_a .dfid } " )
@@ -765,7 +782,8 @@ def main() -> None:
765782 }
766783
767784 result_b = btc_agent .run_decision_cycle (dfid_b , context_b )
768-
785+ record_roa_cycle_result (audit , dfid_b , SIMULATION_ID , result_b , scenario_label = "B" )
786+
769787 if isinstance (result_b , EscalationRequest ):
770788 print (f"\n [RESULT B] EscalationRequest emitted:" )
771789 print (f" DFID: { result_b .dfid } " )
@@ -801,7 +819,8 @@ def main() -> None:
801819 context_c = {"price" : 63500 } # +5.8% profit
802820
803821 result_c = position_agent .run_decision_cycle (dfid_c , context_c )
804-
822+ record_roa_cycle_result (audit , dfid_c , SIMULATION_ID , result_c , scenario_label = "C" )
823+
805824 if isinstance (result_c , PolicyProposal ):
806825 print (f"\n [RESULT C] PositionAgent PolicyProposal:" )
807826 print (f" DFID: { result_c .dfid } " )
@@ -824,7 +843,8 @@ def main() -> None:
824843 context_d = {"price" : 57500 } # -4.2% loss, exceeds 3% max_drawdown_limit
825844
826845 result_d = position_agent .run_decision_cycle (dfid_d , context_d )
827-
846+ record_roa_cycle_result (audit , dfid_d , SIMULATION_ID , result_d , scenario_label = "D" )
847+
828848 if isinstance (result_d , PolicyProposal ):
829849 print (f"\n [RESULT D] Risk-triggered PolicyProposal:" )
830850 print (f" Action: { result_d .policy_kind } " )
@@ -895,7 +915,8 @@ def main() -> None:
895915 }
896916
897917 result_e = restored_agent .run_decision_cycle (dfid_e , context_e )
898-
918+ record_roa_cycle_result (audit , dfid_e , SIMULATION_ID , result_e , scenario_label = "E" )
919+
899920 if isinstance (result_e , PolicyProposal ):
900921 print (f"\n [RESULT E] Restored agent decision:" )
901922 print (f" Action: { result_e .policy_kind } " )
@@ -964,11 +985,17 @@ def main() -> None:
964985 dfid_f1 = new_dfid ()
965986 log_with_dfid (logger , dfid_f1 , logging .INFO , "Growth agent analyzing..." )
966987 result_f1 = growth_agent .run_decision_cycle (dfid_f1 , same_context )
967-
988+ record_roa_cycle_result (
989+ audit , dfid_f1 , SIMULATION_ID , result_f1 , scenario_label = "F_growth"
990+ )
991+
968992 dfid_f2 = new_dfid ()
969993 log_with_dfid (logger , dfid_f2 , logging .INFO , "Defensive agent analyzing..." )
970994 result_f2 = defensive_agent .run_decision_cycle (dfid_f2 , same_context )
971-
995+ record_roa_cycle_result (
996+ audit , dfid_f2 , SIMULATION_ID , result_f2 , scenario_label = "F_defensive"
997+ )
998+
972999 print ("\n [COMPARISON] Same data, different missions:" )
9731000 print (f"\n Growth Agent (mission: 'Maximize alpha...'):" )
9741001 print (f" Focus: opportunity_weight={ growth_agent .parse_mission_focus ()['opportunity_weight' ]:.1f} x" )
@@ -1018,7 +1045,14 @@ def main() -> None:
10181045 dfid_g = new_dfid ()
10191046 log_with_dfid (logger , dfid_g , logging .INFO , f"Challenge { i } : vol={ ctx ['volatility' ]:.1%} " )
10201047 result_g = evolving_agent .run_decision_cycle (dfid_g , ctx )
1021-
1048+ record_roa_cycle_result (
1049+ audit ,
1050+ dfid_g ,
1051+ SIMULATION_ID ,
1052+ result_g ,
1053+ scenario_label = f"G_challenge_{ i } " ,
1054+ )
1055+
10221056 outcome = "ESCALATED" if isinstance (result_g , EscalationRequest ) else result_g .policy_kind
10231057 print (f" Challenge { i } : vol={ ctx ['volatility' ]:.1%} -> { outcome } (policy v{ evolving_agent .state .policy_version } )" )
10241058
@@ -1032,6 +1066,31 @@ def main() -> None:
10321066 print (f" -> Agent { 'shifted to more conservative strategy' if evolving_agent .state .policy_version > 1 else 'maintained original strategy' } " )
10331067
10341068
1069+ def main () -> None :
1070+ """Run ROA demo and append audit rows to canonical SQLite under ``data/``."""
1071+ data_dir = Path (__file__ ).resolve ().parent / "data"
1072+ data_dir .mkdir (parents = True , exist_ok = True )
1073+ db_path = ensure_db (data_dir / "01_roa_agent.db" )
1074+ bundle = sqlite_storage (str (db_path ))
1075+ audit = AuditStore (bundle .decision_audit , bundle .idempotency )
1076+ run_status = "ok"
1077+ end_error : Optional [str ] = None
1078+ try :
1079+ record_simulation_start (audit , SIMULATION_ID )
1080+ _run_roa_demo (audit )
1081+ except Exception as exc :
1082+ run_status = "error"
1083+ end_error = str (exc )
1084+ raise
1085+ finally :
1086+ record_simulation_end (
1087+ audit ,
1088+ SIMULATION_ID ,
1089+ status = run_status ,
1090+ error_message = end_error ,
1091+ )
1092+
1093+
10351094if __name__ == "__main__" :
10361095 main ()
10371096
0 commit comments