fix: harden skipped ledger resolution paths

Co-authored-by: genichin <4282227+genichin@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-08-24 13:38:04 +00:00
committed by GitHub
co-authored by genichin
parent b88b21b772
commit 48dfc3e76f
8 changed files with 451 additions and 96 deletions
+82 -4
View File
@@ -60,6 +60,7 @@ from trex_core.runtime.config import (
_DEFAULT_TIMEOUT = 10.0
_DEFAULT_LEDGER_BACKFILL_AUDIT_DIR = "artifacts/validation/ledger_backfill"
_DEFAULT_LEDGER_SKIP_RESOLVE_AUDIT_DIR = "artifacts/validation/ledger_skip_resolve"
_log = logging.getLogger(__name__)
@@ -406,6 +407,24 @@ def _write_ledger_backfill_audit(args, report: dict) -> str:
return str(path)
def _ledger_skip_resolve_audit_path(args, skip_key: str) -> Path:
base = Path(getattr(args, "audit_dir", _DEFAULT_LEDGER_SKIP_RESOLVE_AUDIT_DIR))
stamp = datetime.now(tz=UTC).strftime("%Y%m%dT%H%M%SZ")
name = (
f"{stamp}--{_sanitize_path_component(_resolve_instance(args))}"
f"--{_sanitize_path_component(skip_key)}.json"
)
return base.resolve() / name
def _write_ledger_skip_resolve_audit(args, report: dict) -> str:
path = _ledger_skip_resolve_audit_path(args, report["request"]["skip_key"])
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(_json.dumps(report, ensure_ascii=False, indent=2, default=str) + "\n",
encoding="utf-8")
return str(path)
def _lookup_ledger_backfill_evidence(cfg: DaemonConfig, *, trading_date: str, execution_id: str):
from trex_core.runtime.broker_provider import build_broker_provider
@@ -661,6 +680,14 @@ def _build_parser() -> argparse.ArgumentParser:
)
p_skips_resolve.add_argument("--skip-key", required=True)
p_skips_resolve.add_argument("--reason", default="operator_reconciled")
p_skips_resolve.add_argument("--yes", action="store_true", help="skip confirmation")
p_skips_resolve.add_argument("--live", action="store_true",
help="confirm a LIVE ledger skip mutation (with --yes)")
p_skips_resolve.add_argument(
"--audit-dir",
default=_DEFAULT_LEDGER_SKIP_RESOLVE_AUDIT_DIR,
help="directory for persistent JSON audit reports",
)
_add_common(p_skips_resolve)
return parser
@@ -1057,13 +1084,61 @@ def _cmd_ledger_skips_list(args, cfg) -> int:
return 0
def _cmd_ledger_skips_resolve(args, cfg) -> int:
def _cmd_ledger_skips_resolve(args, cfg, confirm) -> int:
from trex_core.adapters.persistence.ledger_skip_store import PostgreSQLLedgerSkipStore
instance = _resolve_instance(args)
broker_name, is_live = _broker_mode(cfg)
report = {
"request": {
"instance": instance,
"broker": broker_name,
"live_account": is_live,
"skip_key": args.skip_key,
"resolution_reason": args.reason,
},
"result": None,
"record": None,
"audit_path": None,
}
if is_live and not getattr(args, "live", False):
report["result"] = {"status": "rejected", "reason": "live account requires --live (with --yes)"}
report["audit_path"] = _write_ledger_skip_resolve_audit(args, report)
_fail("live account requires --live (with --yes)", args.json)
if args.json:
_emit(report, as_json=True)
else:
_emit_pretty_json(report)
return 2
if not getattr(args, "yes", False):
if args.json:
report["result"] = {"status": "rejected", "reason": "--json ledger skips resolve requires --yes"}
report["audit_path"] = _write_ledger_skip_resolve_audit(args, report)
_fail("--json ledger skips resolve requires --yes", True)
_emit(report, as_json=True)
return 2
prompt = (
f"Resolve skipped ledger record on instance={instance} broker={broker_name}"
f"{' LIVE' if is_live else ''}: {args.skip_key}?"
)
if not confirm(prompt):
report["result"] = {"status": "aborted", "reason": "operator declined confirmation"}
report["audit_path"] = _write_ledger_skip_resolve_audit(args, report)
print("aborted")
_emit_pretty_json(report)
return 1
store = PostgreSQLLedgerSkipStore(cfg.dsn)
record = store.resolve_by_key(args.skip_key, resolution_reason=args.reason)
record = store.resolve_by_key(
args.skip_key,
instance_key=instance,
resolution_reason=args.reason,
)
if record is None:
report["result"] = {"status": "not_found", "reason": f"unresolved ledger skip not found: {args.skip_key}"}
report["audit_path"] = _write_ledger_skip_resolve_audit(args, report)
_fail(f"unresolved ledger skip not found: {args.skip_key}", args.json)
if args.json:
_emit(report, as_json=True)
return 1
emitter, transport = _default_alarm_emitter(cfg)
try:
@@ -1071,8 +1146,11 @@ def _cmd_ledger_skips_resolve(args, cfg) -> int:
finally:
transport.close()
payload = {"result": "resolved", "record": _render_ledger_skip_record(record)}
report["result"] = {"status": "resolved"}
report["record"] = payload["record"]
report["audit_path"] = _write_ledger_skip_resolve_audit(args, report)
if args.json:
_emit(payload, as_json=True)
_emit({**payload, "audit_path": report["audit_path"]}, as_json=True)
else:
print(f"resolved {record.skip_key} reason={record.resolution_reason}")
return 0
@@ -1338,7 +1416,7 @@ def main(argv: list[str] | None = None, *, rpc=None, confirm=None) -> int:
and getattr(args, "ledger_cmd", None) == "skips"
and getattr(args, "ledger_skips_cmd", None) == "resolve"
):
return _cmd_ledger_skips_resolve(args, cfg)
return _cmd_ledger_skips_resolve(args, cfg, confirm)
# direct-DB control commands (pause/resume stay direct-DB, OQ-3).
if args.cmd in ("pause", "resume", "paused"):
+2
View File
@@ -250,6 +250,8 @@ class Daemon:
retry_cap_sec=config.ledger_retry_cap_sec,
max_attempts=config.ledger_max_attempts,
alarm_emitter=self.alarm_emitter, # dcy-033 / REQ-100
ledger_skip_store=self.ledger_skip_store,
instance_key=config.instance_key,
)
self.kill_switch = KillSwitchService(
slot_repo=self.slot_repo,