Merge pull request 'feat: explicit session_id propagation in logs (#326)' (#336) from feature/issue-326-session-id-explicit-propagation into feature/v3-session-policy-stream
Some checks failed
Gitea CI / test (push) Has been cancelled

Reviewed-on: #336
This commit was merged in pull request #336.
This commit is contained in:
2026-02-28 17:07:34 +09:00
5 changed files with 122 additions and 15 deletions

View File

@@ -109,6 +109,7 @@ def init_db(db_path: str) -> sqlite3.Connection:
stock_code TEXT NOT NULL,
market TEXT NOT NULL,
exchange_code TEXT NOT NULL,
session_id TEXT DEFAULT 'UNKNOWN',
action TEXT NOT NULL,
confidence INTEGER NOT NULL,
rationale TEXT NOT NULL,
@@ -121,6 +122,27 @@ def init_db(db_path: str) -> sqlite3.Connection:
)
"""
)
decision_columns = {
row[1]
for row in conn.execute("PRAGMA table_info(decision_logs)").fetchall()
}
if "session_id" not in decision_columns:
conn.execute("ALTER TABLE decision_logs ADD COLUMN session_id TEXT DEFAULT 'UNKNOWN'")
conn.execute(
"""
UPDATE decision_logs
SET session_id = 'UNKNOWN'
WHERE session_id IS NULL OR session_id = ''
"""
)
if "outcome_pnl" not in decision_columns:
conn.execute("ALTER TABLE decision_logs ADD COLUMN outcome_pnl REAL")
if "outcome_accuracy" not in decision_columns:
conn.execute("ALTER TABLE decision_logs ADD COLUMN outcome_accuracy INTEGER")
if "reviewed" not in decision_columns:
conn.execute("ALTER TABLE decision_logs ADD COLUMN reviewed INTEGER DEFAULT 0")
if "review_notes" not in decision_columns:
conn.execute("ALTER TABLE decision_logs ADD COLUMN review_notes TEXT")
conn.execute(
"""

View File

@@ -19,6 +19,7 @@ class DecisionLog:
stock_code: str
market: str
exchange_code: str
session_id: str
action: str
confidence: int
rationale: str
@@ -47,6 +48,7 @@ class DecisionLogger:
rationale: str,
context_snapshot: dict[str, Any],
input_data: dict[str, Any],
session_id: str | None = None,
) -> str:
"""Log a trading decision with full context.
@@ -59,20 +61,22 @@ class DecisionLogger:
rationale: Reasoning for the decision
context_snapshot: L1-L7 context snapshot at decision time
input_data: Market data inputs (price, volume, orderbook, etc.)
session_id: Runtime session identifier
Returns:
decision_id: Unique identifier for this decision
"""
decision_id = str(uuid.uuid4())
timestamp = datetime.now(UTC).isoformat()
resolved_session = session_id or "UNKNOWN"
self.conn.execute(
"""
INSERT INTO decision_logs (
decision_id, timestamp, stock_code, market, exchange_code,
action, confidence, rationale, context_snapshot, input_data
session_id, action, confidence, rationale, context_snapshot, input_data
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
(
decision_id,
@@ -80,6 +84,7 @@ class DecisionLogger:
stock_code,
market,
exchange_code,
resolved_session,
action,
confidence,
rationale,
@@ -106,7 +111,7 @@ class DecisionLogger:
query = """
SELECT
decision_id, timestamp, stock_code, market, exchange_code,
action, confidence, rationale, context_snapshot, input_data,
session_id, action, confidence, rationale, context_snapshot, input_data,
outcome_pnl, outcome_accuracy, reviewed, review_notes
FROM decision_logs
WHERE reviewed = 0 AND confidence >= ?
@@ -168,7 +173,7 @@ class DecisionLogger:
"""
SELECT
decision_id, timestamp, stock_code, market, exchange_code,
action, confidence, rationale, context_snapshot, input_data,
session_id, action, confidence, rationale, context_snapshot, input_data,
outcome_pnl, outcome_accuracy, reviewed, review_notes
FROM decision_logs
WHERE decision_id = ?
@@ -196,7 +201,7 @@ class DecisionLogger:
"""
SELECT
decision_id, timestamp, stock_code, market, exchange_code,
action, confidence, rationale, context_snapshot, input_data,
session_id, action, confidence, rationale, context_snapshot, input_data,
outcome_pnl, outcome_accuracy, reviewed, review_notes
FROM decision_logs
WHERE confidence >= ?
@@ -223,13 +228,14 @@ class DecisionLogger:
stock_code=row[2],
market=row[3],
exchange_code=row[4],
action=row[5],
confidence=row[6],
rationale=row[7],
context_snapshot=json.loads(row[8]),
input_data=json.loads(row[9]),
outcome_pnl=row[10],
outcome_accuracy=row[11],
reviewed=bool(row[12]),
review_notes=row[13],
session_id=row[5] or "UNKNOWN",
action=row[6],
confidence=row[7],
rationale=row[8],
context_snapshot=json.loads(row[9]),
input_data=json.loads(row[10]),
outcome_pnl=row[11],
outcome_accuracy=row[12],
reviewed=bool(row[13]),
review_notes=row[14],
)

View File

@@ -217,6 +217,7 @@ async def sync_positions_from_broker(
price=avg_price,
market=log_market,
exchange_code=market.exchange_code,
session_id=get_session_info(market).session_id,
mode=settings.MODE,
)
logger.info(
@@ -1368,10 +1369,12 @@ async def trading_cycle(
"pnl_pct": pnl_pct,
}
runtime_session_id = get_session_info(market).session_id
decision_id = decision_logger.log_decision(
stock_code=stock_code,
market=market.code,
exchange_code=market.exchange_code,
session_id=runtime_session_id,
action=decision.action,
confidence=decision.confidence,
rationale=decision.rationale,
@@ -1636,6 +1639,7 @@ async def trading_cycle(
pnl=0.0,
market=market.code,
exchange_code=market.exchange_code,
session_id=runtime_session_id,
mode=settings.MODE if settings else "paper",
)
logger.info("Order result: %s", result.get("msg1", "OK"))
@@ -1690,6 +1694,7 @@ async def trading_cycle(
pnl=trade_pnl,
market=market.code,
exchange_code=market.exchange_code,
session_id=runtime_session_id,
selection_context=selection_context,
decision_id=decision_id,
mode=settings.MODE if settings else "paper",
@@ -2497,10 +2502,12 @@ async def run_daily_session(
"pnl_pct": pnl_pct,
}
runtime_session_id = get_session_info(market).session_id
decision_id = decision_logger.log_decision(
stock_code=stock_code,
market=market.code,
exchange_code=market.exchange_code,
session_id=runtime_session_id,
action=decision.action,
confidence=decision.confidence,
rationale=decision.rationale,
@@ -2777,6 +2784,7 @@ async def run_daily_session(
pnl=trade_pnl,
market=market.code,
exchange_code=market.exchange_code,
session_id=runtime_session_id,
decision_id=decision_id,
mode=settings.MODE,
)