fix: guard unmanaged resolution on authoritative balances
Co-authored-by: genichin <4282227+genichin@users.noreply.github.com>
This commit is contained in:
co-authored by
genichin
parent
f2b825e720
commit
5a13c0494b
@@ -35,6 +35,11 @@ class RaisingBroker(FakeBroker):
|
||||
raise BrokerBalanceError("transport_failed")
|
||||
|
||||
|
||||
class FilteredBroker(FakeBroker):
|
||||
def exposes_full_balance_snapshot(self) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def _wire():
|
||||
repo = InMemorySlotRepository()
|
||||
return repo, SlotService(repo, instance_key=INSTANCE)
|
||||
@@ -188,3 +193,22 @@ def test_broker_failure_does_not_resolve_unmanaged_state():
|
||||
state = store.get_state(instance_key=INSTANCE, symbol="008110")
|
||||
assert state is not None
|
||||
assert state["lifecycle_state"] == "active"
|
||||
|
||||
|
||||
def test_non_authoritative_broker_view_does_not_resolve_unmanaged_state():
|
||||
repo, svc = _wire()
|
||||
store = InMemoryUnmanagedPositionStore()
|
||||
store.observe(instance_key=INSTANCE, symbol="008110", quantity=3)
|
||||
|
||||
decisions = reconcile_core_holdings(
|
||||
slot_repo=repo,
|
||||
slot_service=svc,
|
||||
broker=FilteredBroker({}),
|
||||
instance_key=INSTANCE,
|
||||
unmanaged_position_store=store,
|
||||
)
|
||||
|
||||
assert decisions == {}
|
||||
state = store.get_state(instance_key=INSTANCE, symbol="008110")
|
||||
assert state is not None
|
||||
assert state["lifecycle_state"] == "active"
|
||||
|
||||
@@ -593,6 +593,7 @@ def test_unmanaged_list_outputs_durable_state(monkeypatch, capsys):
|
||||
assert rc == 0
|
||||
out = json.loads(capsys.readouterr().out)
|
||||
assert out["count"] == 1
|
||||
assert out["instance_key"] == "inst-1"
|
||||
assert out["states"][0]["symbol"] == "008110"
|
||||
assert out["states"][0]["evidence_ref"] == "kis-balance:2026-09-11"
|
||||
|
||||
@@ -688,6 +689,58 @@ def test_unmanaged_record_persists_operator_action(monkeypatch, capsys):
|
||||
assert out["state"]["evidence_ref"] == "kis-balance:2026-09-11"
|
||||
|
||||
|
||||
def test_unmanaged_record_text_output(monkeypatch, capsys):
|
||||
class _Store:
|
||||
def __init__(self, *_args, **_kwargs):
|
||||
pass
|
||||
|
||||
def record_operator_action(self, **kwargs):
|
||||
return {
|
||||
"instance_key": "inst-1",
|
||||
"symbol": kwargs["symbol"],
|
||||
"quantity": 3,
|
||||
"lifecycle_state": "active",
|
||||
"first_seen_at": "2026-09-07T00:00:00+00:00",
|
||||
"last_seen_at": "2026-09-11T00:00:00+00:00",
|
||||
"quantity_changed_at": "2026-09-07T00:00:00+00:00",
|
||||
"resolved_at": None,
|
||||
"operator_action": kwargs["action"],
|
||||
"evidence_ref": kwargs["evidence_ref"],
|
||||
"operator_note": kwargs["note"],
|
||||
"operator_actor": kwargs["actor"],
|
||||
"operator_updated_at": "2026-09-11T00:00:00+00:00",
|
||||
"created_at": "2026-09-07T00:00:00+00:00",
|
||||
"updated_at": "2026-09-11T00:00:00+00:00",
|
||||
}
|
||||
|
||||
monkeypatch.setattr(
|
||||
"trex_core.adapters.portfolio.unmanaged_position_store.PostgreSQLUnmanagedPositionStore",
|
||||
_Store,
|
||||
)
|
||||
args = SimpleNamespace(
|
||||
cmd="unmanaged",
|
||||
unmanaged_cmd="record",
|
||||
symbol="008110",
|
||||
action="approved_exception",
|
||||
evidence_ref="kis-balance:2026-09-11",
|
||||
note="confirmed",
|
||||
actor="operator",
|
||||
instance="inst-1",
|
||||
config=None,
|
||||
config_path=None,
|
||||
env_file=None,
|
||||
json=False,
|
||||
timeout=10.0,
|
||||
)
|
||||
|
||||
rc = cli._cmd_unmanaged_record(args, SimpleNamespace(dsn="postgresql://x/y"))
|
||||
|
||||
assert rc == 0
|
||||
out = capsys.readouterr().out
|
||||
assert "recorded unmanaged position instance=inst-1 symbol=008110" in out
|
||||
assert "evidence_ref=kis-balance:2026-09-11" in out
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# REL-010 regression: _cmd_verify broker import must not raise ImportError
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user