From c13328b2999023aaf73f8ebf284c01d0096be7c8 Mon Sep 17 00:00:00 2001 From: Brian McMahon Date: Thu, 4 Jun 2026 15:49:15 -0700 Subject: [PATCH] SF: add non-fatal Director state as the final Saturday-SF task (after ReportCard) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Director (Layer C, Part II) runs as the FINAL Saturday-SF task, after a SUCCESSFUL ReportCard, weighing the fresh Report Card v2 → an advisory DirectorWeeklyActionPlan. Wiring: WaitForWeeklySubstrateHealthCheck → ReportCard → Director → CheckShellRunNotify - ReportCard SUCCESS Next → Director (feeds it the fresh card). - ReportCard Catch → CheckShellRunNotify (skip the Director — no card to weigh). - Director Next AND its own Catch → CheckShellRunNotify (non-fatal: an advisory failure never breaks the run that produced the real trading artifacts). - Invokes alpha-engine-evaluator-director:live with {date.$: $.run_date}. FLAG-GATED: the function is a no-op (status=disabled) until DIRECTOR_ENABLED is flipped on after a clean Saturday cycle. SF-role IAM: no change — the existing alpha-engine-evaluator* invoke grant already covers alpha-engine-evaluator-director (asserted by test_sf_iam_lambda_grants::test_every_invoked_lambda_has_iam_grant). Guardrail tests updated: substrate-check + friday-shell-run wiring now assert the ReportCard→Director→notify path (both Director edges land on the notify gate); payload registry adds "Director": {date.$}. 596 SF tests green. Co-Authored-By: Claude Opus 4.8 (1M context) --- infrastructure/step_function.json | 35 ++++++++++++++++++++++++ tests/test_sf_friday_shell_run_wiring.py | 15 ++++++---- tests/test_sf_payload_uniqueness.py | 4 +++ tests/test_sf_substrate_check_wiring.py | 13 ++++++--- 4 files changed, 58 insertions(+), 9 deletions(-) diff --git a/infrastructure/step_function.json b/infrastructure/step_function.json index 462ac74..bd2d12d 100644 --- a/infrastructure/step_function.json +++ b/infrastructure/step_function.json @@ -2287,6 +2287,41 @@ } ], "ResultPath": "$.report_card_result", + "Next": "Director" + }, + "Director": { + "Type": "Task", + "Comment": "Director (Layer C, Part II) — the FINAL Saturday-SF task. A single structured Opus call over the fresh Report Card v2 (evaluator/{date}/report_card.json) produces an advisory DirectorWeeklyActionPlan at director/{date}/action_plan.json + updates the carry-over ledger. Runs only after a SUCCESSFUL ReportCard (a failed ReportCard skips straight to notify — no card to weigh). FLAG-GATED: the alpha-engine-evaluator-director Lambda is a no-op (status=disabled) until DIRECTOR_ENABLED is flipped on. NON-FATAL: its own Catch routes to CheckShellRunNotify so an advisory failure never breaks the run that produced the real trading artifacts.", + "Resource": "arn:aws:states:::lambda:invoke", + "Parameters": { + "FunctionName": "alpha-engine-evaluator-director:live", + "Payload": { + "date.$": "$.run_date" + } + }, + "TimeoutSeconds": 300, + "Retry": [ + { + "ErrorEquals": [ + "Lambda.ServiceException", + "Lambda.TooManyRequestsException" + ], + "MaxAttempts": 1, + "IntervalSeconds": 30, + "BackoffRate": 1.0 + } + ], + "Catch": [ + { + "ErrorEquals": [ + "States.ALL" + ], + "Comment": "Advisory Director is non-fatal — continue to the terminal notify regardless.", + "Next": "CheckShellRunNotify", + "ResultPath": "$.director_error" + } + ], + "ResultPath": "$.director_result", "Next": "CheckShellRunNotify" }, "CheckShellRunNotify": { diff --git a/tests/test_sf_friday_shell_run_wiring.py b/tests/test_sf_friday_shell_run_wiring.py index 5d2ff47..904f2e1 100644 --- a/tests/test_sf_friday_shell_run_wiring.py +++ b/tests/test_sf_friday_shell_run_wiring.py @@ -674,16 +674,21 @@ def test_dry_lambda_payload_references_control_var( class TestConsolidatedNotify: def test_substrate_check_routes_to_notify_gate(self, states): - # The substrate check now flows through the non-fatal ReportCard state - # (evaluator Report Card v2) before the notify gate; ReportCard's success - # Next AND its Catch both land on CheckShellRunNotify, so the path to the - # notify gate is preserved whether grading succeeds or fails. + # The substrate check now flows through two non-fatal advisory states + # (evaluator Report Card v2, then the Director) before the notify gate. + # ReportCard's SUCCESS Next feeds the Director; its Catch skips straight + # to CheckShellRunNotify. The Director's own Next AND Catch both land on + # CheckShellRunNotify, so the path to the notify gate is preserved + # whether grading/advisory succeed or fail. assert ( states["WaitForWeeklySubstrateHealthCheck"]["Next"] == "ReportCard" ) report_card = states["ReportCard"] - assert report_card["Next"] == "CheckShellRunNotify" + assert report_card["Next"] == "Director" assert all(c["Next"] == "CheckShellRunNotify" for c in report_card["Catch"]) + director = states["Director"] + assert director["Next"] == "CheckShellRunNotify" + assert all(c["Next"] == "CheckShellRunNotify" for c in director["Catch"]) def test_shell_run_notify_reuses_sns_substrate(self, states): """NotifyShellRunComplete surfaces the user-facing 'Saturday diff --git a/tests/test_sf_payload_uniqueness.py b/tests/test_sf_payload_uniqueness.py index c6d2e4b..aca708a 100644 --- a/tests/test_sf_payload_uniqueness.py +++ b/tests/test_sf_payload_uniqueness.py @@ -106,6 +106,10 @@ def _flatten_states(sf_doc: dict) -> dict: # Evaluator Report Card v2 (Layer B) — alpha-engine-evaluator:live. Builds # evaluator/{date}/report_card.json; non-fatal (own Catch → notify gate). "ReportCard": frozenset({"date.$"}), + # Director (Layer C, Part II) — alpha-engine-evaluator-director:live. Final + # advisory task; reads the fresh report card, writes director/{date}/ + # action_plan.json; flag-gated (DIRECTOR_ENABLED) + non-fatal (own Catch). + "Director": frozenset({"date.$"}), } # Weekday SF — alpha-engine-predictor Lambdas diff --git a/tests/test_sf_substrate_check_wiring.py b/tests/test_sf_substrate_check_wiring.py index be26020..22aede8 100644 --- a/tests/test_sf_substrate_check_wiring.py +++ b/tests/test_sf_substrate_check_wiring.py @@ -77,14 +77,19 @@ def test_wait_for_substrate_routes_to_notify_complete(self, states): # unchanged NotifyComplete, so the REAL Saturday run (no shell_run # input) still ends at NotifyComplete — strict superset preserved. # - # The non-fatal ReportCard state (evaluator Report Card v2) now sits - # between the substrate poll and the notify gate; both its Next and its - # Catch land on CheckShellRunNotify, preserving the success edge. + # Two non-fatal advisory states (evaluator Report Card v2, then the + # Director) now sit between the substrate poll and the notify gate. + # ReportCard's SUCCESS edge feeds the Director (which weighs the fresh + # card); ReportCard's Catch skips the Director straight to notify (no + # card to weigh). The Director's own Next AND Catch both land on + # CheckShellRunNotify, so every path still preserves the success edge. assert ( states["WaitForWeeklySubstrateHealthCheck"]["Next"] == "ReportCard" ) - assert states["ReportCard"]["Next"] == "CheckShellRunNotify" + assert states["ReportCard"]["Next"] == "Director" assert all(c["Next"] == "CheckShellRunNotify" for c in states["ReportCard"]["Catch"]) + assert states["Director"]["Next"] == "CheckShellRunNotify" + assert all(c["Next"] == "CheckShellRunNotify" for c in states["Director"]["Catch"]) assert states["CheckShellRunNotify"]["Default"] == "NotifyComplete"