feat: persist unmanaged position lifecycle state

Co-authored-by: genichin <4282227+genichin@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-09-12 13:24:51 +00:00
committed by GitHub
co-authored by genichin
parent ae2e598209
commit fe51d211d9
12 changed files with 1274 additions and 5 deletions
+169
View File
@@ -516,6 +516,175 @@ def test_verify_no_db_no_live_flag_needed(capsys, monkeypatch):
assert rc == 0
# ---------------------------------------------------------------------------
# unmanaged parser/tests
# ---------------------------------------------------------------------------
def test_unmanaged_parser_accepts_list_and_record():
parser = cli._build_parser()
args = parser.parse_args(["unmanaged", "list", "--status", "all", "--symbol", "008110"])
assert args.cmd == "unmanaged"
assert args.unmanaged_cmd == "list"
assert args.status == "all"
args = parser.parse_args(
[
"unmanaged",
"record",
"008110",
"investigating",
"--evidence-ref",
"kis-balance:2026-09-11",
]
)
assert args.unmanaged_cmd == "record"
assert args.action == "investigating"
def test_unmanaged_list_outputs_durable_state(monkeypatch, capsys):
class _Store:
def __init__(self, *_args, **_kwargs):
pass
def list_states(self, **kwargs):
assert kwargs["instance_key"] == "inst-1"
assert kwargs["lifecycle_state"] == "all"
return [
{
"instance_key": "inst-1",
"symbol": "008110",
"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": "investigating",
"evidence_ref": "kis-balance:2026-09-11",
"operator_note": "confirmed",
"operator_actor": "operator",
"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="list",
status="all",
symbol=None,
instance="inst-1",
config=None,
config_path=None,
env_file=None,
json=True,
timeout=10.0,
)
rc = cli._cmd_unmanaged_list(args, SimpleNamespace(dsn="postgresql://x/y"))
assert rc == 0
out = json.loads(capsys.readouterr().out)
assert out["count"] == 1
assert out["states"][0]["symbol"] == "008110"
assert out["states"][0]["evidence_ref"] == "kis-balance:2026-09-11"
def test_unmanaged_record_requires_existing_state(monkeypatch, capsys):
class _Store:
def __init__(self, *_args, **_kwargs):
pass
def record_operator_action(self, **_kwargs):
return None
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=True,
timeout=10.0,
)
rc = cli._cmd_unmanaged_record(args, SimpleNamespace(dsn="postgresql://x/y"))
assert rc == 1
err = json.loads(capsys.readouterr().err)
assert "not found" in err["error"]
def test_unmanaged_record_persists_operator_action(monkeypatch, capsys):
class _Store:
def __init__(self, *_args, **_kwargs):
pass
def record_operator_action(self, **kwargs):
assert kwargs["instance_key"] == "inst-1"
assert kwargs["symbol"] == "008110"
assert kwargs["action"] == "managed_inclusion"
return {
"instance_key": "inst-1",
"symbol": "008110",
"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": "managed_inclusion",
"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="managed_inclusion",
evidence_ref="kis-balance:2026-09-11",
note="manual inclusion planned",
actor="operator",
instance="inst-1",
config=None,
config_path=None,
env_file=None,
json=True,
timeout=10.0,
)
rc = cli._cmd_unmanaged_record(args, SimpleNamespace(dsn="postgresql://x/y"))
assert rc == 0
out = json.loads(capsys.readouterr().out)
assert out["result"] == "recorded"
assert out["state"]["operator_action"] == "managed_inclusion"
assert out["state"]["evidence_ref"] == "kis-balance:2026-09-11"
# ---------------------------------------------------------------------------
# REL-010 regression: _cmd_verify broker import must not raise ImportError
# ---------------------------------------------------------------------------