Skip to content

Commit 56c6733

Browse files
Pigbibicodex
andcommitted
fix: fail closed and suppress non-execution heartbeats
Co-Authored-By: Codex <noreply@openai.com>
1 parent 3a2149a commit 56c6733

6 files changed

Lines changed: 109 additions & 3 deletions

decision_mapper.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,14 @@ def map_strategy_decision(
148148
diagnostics["consecutive_losses"] = int(runtime_metadata["consecutive_losses"])
149149
risk_flags = tuple(str(flag) for flag in decision.risk_flags)
150150
no_execute = bool(_NO_EXECUTE_FLAGS & set(risk_flags))
151+
if not no_execute and not decision.positions:
152+
# An empty position set is not a safe implicit liquidation instruction.
153+
# It can result from a degraded strategy plug-in or missing inputs, so
154+
# keep the existing book unchanged until a strategy explicitly emits a
155+
# releasable allocation.
156+
no_execute = True
157+
risk_flags = tuple(dict.fromkeys((*risk_flags, "no_execute")))
158+
diagnostics.setdefault("execution_blocked_reason", "empty_position_decision")
151159
total_equity_value = runtime_metadata.get("portfolio_total_equity")
152160
cash_only_execution = bool(runtime_metadata.get("cash_only_execution", True))
153161
if not no_execute and total_equity_value is not None:

scripts/execution_report_heartbeat.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
match_payload_target,
2323
runtime_target_configuration_has_enabled_targets,
2424
runtime_target_configuration_present,
25+
runtime_target_permits_standard_execution,
2526
target_key,
2627
target_label,
2728
target_latest_due_at,
@@ -34,6 +35,7 @@
3435
match_payload_target,
3536
runtime_target_configuration_has_enabled_targets,
3637
runtime_target_configuration_present,
38+
runtime_target_permits_standard_execution,
3739
target_key,
3840
target_label,
3941
target_latest_due_at,
@@ -124,7 +126,10 @@ def _target_enabled(target: dict[str, Any], runtime_target: dict[str, Any]) -> b
124126
value = target.get("RUNTIME_TARGET_ENABLED")
125127
if value is None:
126128
value = runtime_target.get("runtime_target_enabled")
127-
return _enabled_value(value, default=True)
129+
return (
130+
_enabled_value(value, default=True)
131+
and runtime_target_permits_standard_execution(runtime_target)
132+
)
128133

129134

130135
def _target_service_values(target: dict[str, Any], runtime_target: dict[str, Any]) -> list[str]:

scripts/runtime_heartbeat_policy.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,21 @@ def _enabled(value: Any, *, default: bool = True) -> bool:
4949
return str(value).strip().lower() not in {"0", "false", "no", "n", "off"}
5050

5151

52+
def runtime_target_permits_standard_execution(runtime_target: Mapping[str, Any]) -> bool:
53+
"""Return whether normal execution receipts are expected for a target.
54+
55+
A continuity record deliberately distinguishes an authorised live baseline
56+
from reconciliation, pause, and specialised risk-reduction states. The
57+
generic heartbeat must not demand a normal execution report when the
58+
runtime is explicitly prohibited from normal execution; those states are
59+
verified by their dedicated reconciliation controls instead.
60+
"""
61+
62+
continuity = _mapping(runtime_target.get("live_continuity"))
63+
state = str(continuity.get("state") or "").strip().upper()
64+
return not state or state in {"ACTIVE_LKG", "ROLLBACK_LKG"}
65+
66+
5267
def _mapping(value: Any) -> Mapping[str, Any]:
5368
return value if isinstance(value, Mapping) else {}
5469

@@ -317,7 +332,7 @@ def runtime_target_configuration_has_enabled_targets(
317332
)
318333
if enabled_value is None:
319334
enabled_value = runtime_target.get("runtime_target_enabled")
320-
if _enabled(enabled_value):
335+
if _enabled(enabled_value) and runtime_target_permits_standard_execution(runtime_target):
321336
return True
322337
return False
323338

@@ -342,7 +357,10 @@ def load_runtime_targets(
342357
)
343358
if enabled_value is None:
344359
enabled_value = runtime_target.get("runtime_target_enabled")
345-
enabled = _enabled(enabled_value)
360+
enabled = (
361+
_enabled(enabled_value)
362+
and runtime_target_permits_standard_execution(runtime_target)
363+
)
346364
if not enabled and not include_disabled:
347365
continue
348366
target_scope = _first_value(

tests/test_decision_mapper.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,25 @@ def test_map_strategy_decision_returns_noop_when_flagged_no_execute():
6666
assert "allocation" not in metadata
6767

6868

69+
def test_map_strategy_decision_fails_closed_for_unflagged_empty_positions():
70+
target_weights, _signal_desc, _is_emergency, _status_desc, metadata = map_strategy_decision(
71+
StrategyDecision(
72+
diagnostics={
73+
"signal_description": "strategy input unavailable",
74+
"status_description": "waiting",
75+
}
76+
),
77+
strategy_profile="soxl_soxx_trend_income",
78+
runtime_metadata={"managed_symbols": ("SOXL", "SOXX", "BOXX")},
79+
)
80+
81+
assert target_weights is None
82+
assert metadata["actionable"] is False
83+
assert metadata["execution_blocked_reason"] == "empty_position_decision"
84+
assert metadata["risk_flags"] == ("no_execute",)
85+
assert "allocation" not in metadata
86+
87+
6988
def test_map_strategy_decision_translates_value_targets_for_semiconductor_strategy():
7089
decision = StrategyDecision(
7190
positions=(

tests/test_execution_report_heartbeat.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,40 @@ def test_target_derived_required_services_skip_disabled_targets(monkeypatch):
9898
]
9999

100100

101+
def test_target_derived_required_services_skip_reconcile_only_targets(monkeypatch):
102+
monkeypatch.delenv("RUNTIME_HEARTBEAT_REQUIRED_SERVICES", raising=False)
103+
monkeypatch.delenv("CLOUD_RUN_SERVICE", raising=False)
104+
monkeypatch.delenv("CLOUD_RUN_SERVICES", raising=False)
105+
monkeypatch.delenv("RUNTIME_HEARTBEAT_ACCOUNT_SCOPE", raising=False)
106+
monkeypatch.setenv(
107+
"CLOUD_RUN_SERVICE_TARGETS_JSON",
108+
json.dumps(
109+
{
110+
"targets": [
111+
{
112+
"service": "reconcile-only-service",
113+
"runtime_target": {
114+
"service_name": "reconcile-only-service",
115+
"strategy_profile": "strategy-a",
116+
"live_continuity": {"state": "RECONCILE_ONLY"},
117+
},
118+
},
119+
{
120+
"service": "active-service",
121+
"runtime_target": {
122+
"service_name": "active-service",
123+
"strategy_profile": "strategy-b",
124+
"live_continuity": {"state": "ACTIVE_LKG"},
125+
},
126+
},
127+
]
128+
}
129+
),
130+
)
131+
132+
assert heartbeat._load_required_services() == ["active-service"]
133+
134+
101135
def test_explicit_required_services_skip_disabled_targets(monkeypatch):
102136
monkeypatch.setenv(
103137
"RUNTIME_HEARTBEAT_REQUIRED_SERVICES",

tests/test_runtime_heartbeat_policy.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,28 @@ def test_target_defaults_and_scheduler_aliases_are_normalized() -> None:
276276
}
277277

278278

279+
def test_reconcile_only_target_is_not_an_execution_heartbeat_target() -> None:
280+
environ = {
281+
"CLOUD_RUN_SERVICE_TARGETS_JSON": json.dumps(
282+
{
283+
"targets": [
284+
{
285+
"service": "reconcile-only-service",
286+
"runtime_target": {
287+
"service_name": "reconcile-only-service",
288+
"strategy_profile": "strategy-a",
289+
"live_continuity": {"state": "RECONCILE_ONLY"},
290+
},
291+
}
292+
]
293+
}
294+
)
295+
}
296+
297+
assert load_runtime_targets(environ) == []
298+
assert runtime_target_configuration_present(environ) is True
299+
300+
279301

280302
def test_publication_grace_uses_previous_matured_schedule_cutoff() -> None:
281303
targets = load_runtime_targets(

0 commit comments

Comments
 (0)