mirror of
https://github.com/TauricResearch/TradingAgents.git
synced 2026-09-19 19:25:24 +03:00
fix(memory): keep a settled decision from being logged twice
- the duplicate guard matched only pending entries, so re-running a settled ticker and date appended a second one
This commit is contained in:
@@ -136,6 +136,23 @@ class TestTradingMemoryLogCore:
|
|||||||
log.store_decision("NVDA", "2026-01-10", DECISION_BUY)
|
log.store_decision("NVDA", "2026-01-10", DECISION_BUY)
|
||||||
assert len(log.load_entries()) == 1
|
assert len(log.load_entries()) == 1
|
||||||
|
|
||||||
|
def test_store_decision_idempotent_after_the_entry_resolves(self, tmp_path):
|
||||||
|
"""A settled entry still blocks a duplicate.
|
||||||
|
|
||||||
|
The guard matched only pending entries, so re-running a ticker and date
|
||||||
|
whose outcome had already been settled appended a second entry: the same
|
||||||
|
decision counted twice in past context and in any aggregate over the log.
|
||||||
|
"""
|
||||||
|
log = make_log(tmp_path)
|
||||||
|
log.store_decision("NVDA", "2026-01-10", DECISION_BUY)
|
||||||
|
log.update_with_outcome("NVDA", "2026-01-10", 0.05, 0.02, 5, "worked", "2026-01-17")
|
||||||
|
|
||||||
|
log.store_decision("NVDA", "2026-01-10", DECISION_BUY)
|
||||||
|
|
||||||
|
entries = log.load_entries()
|
||||||
|
assert len(entries) == 1
|
||||||
|
assert entries[0]["pending"] is False # the settled record is kept, not replaced
|
||||||
|
|
||||||
def test_batch_update_resolves_multiple_entries(self, tmp_path):
|
def test_batch_update_resolves_multiple_entries(self, tmp_path):
|
||||||
"""batch_update_with_outcomes resolves multiple pending entries in one write."""
|
"""batch_update_with_outcomes resolves multiple pending entries in one write."""
|
||||||
log = make_log(tmp_path)
|
log = make_log(tmp_path)
|
||||||
|
|||||||
@@ -36,11 +36,14 @@ class TradingMemoryLog:
|
|||||||
"""Append pending entry at end of propagate(). No LLM call."""
|
"""Append pending entry at end of propagate(). No LLM call."""
|
||||||
if not self._log_path:
|
if not self._log_path:
|
||||||
return
|
return
|
||||||
# Idempotency guard: fast raw-text scan instead of full parse
|
# Idempotency guard: fast raw-text scan instead of full parse. Any entry
|
||||||
|
# for this ticker and date blocks another, pending or settled: a re-run
|
||||||
|
# after the outcome landed would otherwise count the same decision twice
|
||||||
|
# in past context and in every aggregate over the log.
|
||||||
if self._log_path.exists():
|
if self._log_path.exists():
|
||||||
raw = self._log_path.read_text(encoding="utf-8")
|
raw = self._log_path.read_text(encoding="utf-8")
|
||||||
for line in raw.splitlines():
|
for line in raw.splitlines():
|
||||||
if line.startswith(f"[{trade_date} | {ticker} |") and line.endswith("| pending]"):
|
if line.startswith(f"[{trade_date} | {ticker} |") and line.endswith("]"):
|
||||||
return
|
return
|
||||||
rating = parse_rating(final_trade_decision)
|
rating = parse_rating(final_trade_decision)
|
||||||
tag = f"[{trade_date} | {ticker} | {rating} | pending]"
|
tag = f"[{trade_date} | {ticker} | {rating} | pending]"
|
||||||
|
|||||||
Reference in New Issue
Block a user